From 1d5ee492ad7e0d0ee6a4886bb248e756f1ccb03f Mon Sep 17 00:00:00 2001 From: Rey Date: Mon, 24 Dec 2018 14:54:51 +0800 Subject: [PATCH] float animation % synced changes --- .gitmodules | 3 + README.md | 15 +- app/listen1_chrome_extension/README.md | 27 +- app/listen1_chrome_extension/README_EN.md | 56 + app/listen1_chrome_extension/css/cover.css | 43 +- .../css/hover-min.css | 9 + app/listen1_chrome_extension/css/icon.css | 89 + .../css/iparanoid.css | 1345 ++ app/listen1_chrome_extension/css/player.css | 264 +- .../fonts/listen1-icon.eot | Bin 0 -> 3644 bytes .../fonts/listen1-icon.svg | 31 + .../fonts/listen1-icon.ttf | Bin 0 -> 3460 bytes .../fonts/listen1-icon.woff | Bin 0 -> 3536 bytes app/listen1_chrome_extension/i18n/en_US.json | 85 + app/listen1_chrome_extension/i18n/zh_CN.json | 85 + .../images/feather-sprite.svg | 1 + .../images/loading.svg | 1 + app/listen1_chrome_extension/js/app.js | 386 +- app/listen1_chrome_extension/js/background.js | 18 +- app/listen1_chrome_extension/js/github.js | 35 +- app/listen1_chrome_extension/js/myplaylist.js | 5 +- .../js/provider/bilibili.js | 70 +- .../js/provider/kugou.js | 40 +- .../js/provider/netease.js | 261 +- .../js/provider/qq.js | 10 + .../js/provider/xiami.js | 131 +- .../js/vendor/angular-soundmanager2.js | 10557 +++++++++------- ...gular-translate-loader-static-files.min.js | 6 + .../js/vendor/angular-translate.min.js | 6 + .../js/vendor/angular.min.js | 677 +- .../js/vendor/jquery-3.3.1.min.js | 2 + app/listen1_chrome_extension/listen1.html | 864 +- app/listen1_chrome_extension/manifest.json | 6 +- .../manifest_firefox.json | 8 +- app/main.js | 252 +- app/package.json | 10 +- package.json | 160 +- 37 files changed, 9655 insertions(+), 5903 deletions(-) create mode 100644 .gitmodules create mode 100644 app/listen1_chrome_extension/README_EN.md create mode 100644 app/listen1_chrome_extension/css/hover-min.css create mode 100644 app/listen1_chrome_extension/css/icon.css create mode 100644 app/listen1_chrome_extension/css/iparanoid.css create mode 100644 app/listen1_chrome_extension/fonts/listen1-icon.eot create mode 100644 app/listen1_chrome_extension/fonts/listen1-icon.svg create mode 100644 app/listen1_chrome_extension/fonts/listen1-icon.ttf create mode 100644 app/listen1_chrome_extension/fonts/listen1-icon.woff create mode 100644 app/listen1_chrome_extension/i18n/en_US.json create mode 100644 app/listen1_chrome_extension/i18n/zh_CN.json create mode 100644 app/listen1_chrome_extension/images/feather-sprite.svg create mode 100644 app/listen1_chrome_extension/images/loading.svg create mode 100644 app/listen1_chrome_extension/js/vendor/angular-translate-loader-static-files.min.js create mode 100644 app/listen1_chrome_extension/js/vendor/angular-translate.min.js create mode 100644 app/listen1_chrome_extension/js/vendor/jquery-3.3.1.min.js diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..92e751b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "app/listen1_chrome_extension"] + path = app/listen1_chrome_extension + url = git@github.com:listen1/listen1_chrome_extension.git diff --git a/README.md b/README.md index 5f2f6f4..b936a8d 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,22 @@ Listen 1可以搜索和播放来自网易云音乐,虾米,QQ音乐三个主 本版和[原版](https://github.com/listen1/listen1_desktop/releases/tag/v2.0.0)对比: ---- - 毛玻璃样式、去除无用框线 +- 添加专辑封面浮动动画 - 添加 空格键 暂停/继续 播放快捷键(非全局不会占用) - UI 细节透明适配 + +最近更新 (2018-12-24) [ [Version 2.1.0](https://github.com/oyrx/listen1_desktop_fluent/releases/tag/2.1.0) ]: +---- +- 添加专辑封面浮动动画 +- 同步原版改动: +-- Bug fix +-- English translation -[2.0.0](https://github.com/oyrx/listen1_desktop_fluent/releases/tag/2.0.0) 更新: + +历史更新 ---- + +[2.0.0](https://github.com/oyrx/listen1_desktop_fluent/releases/tag/2.0.0) - 全新版本2.0发布,更新界面(特别感谢@iparanoid提供主题设计) - 增加全局快捷键支持 - linux系统适配 (Fluent版本暂时不支持) @@ -24,8 +35,6 @@ Listen 1可以搜索和播放来自网易云音乐,虾米,QQ音乐三个主 - 修复Github Gist备份无法导入的问题 - 升级soundmanager2库到最新版本 -历史更新 ----- [1.9.0](https://github.com/oyrx/listen1_desktop_fluent/releases/tag/1.9.0) - 同步上游代码(除虾米) - 网易云现在可以正常打开所有歌单了 diff --git a/app/listen1_chrome_extension/README.md b/app/listen1_chrome_extension/README.md index dc3caf9..a463a49 100644 --- a/app/listen1_chrome_extension/README.md +++ b/app/listen1_chrome_extension/README.md @@ -1,9 +1,11 @@ -Listen 1 (Chrome Extension) V1.9.0 +Listen 1 (Chrome Extension) V2.1.0 ========== -(最后更新于2018年12月5日) +(最后更新于2018年12月24日) [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE) +[English Version](https://github.com/listen1/listen1_chrome_extension/blob/master/README_EN.md) + 重要 ---- Listen1的用户,有个坏消息希望和大家分享。Listen1最近收到了[QQ音乐的DMCA Takedown Notice](https://github.com/github/dmca/blob/master/2017/2017-11-17-Listen1.md), 主要代码库已经因为此原因而临时关闭。悲观一点看,Listen1项目可能会在今年内彻底消失。 @@ -44,6 +46,22 @@ Firefox打包安装 更新日志 ------- +`2018-12-24` +* 多语言支持,支持英文 +* 新添加到歌单的歌曲将出现在歌单头部 +* 修复版权通知占满屏幕的bug + +`2018-12-22` +* 全新版本2.0发布,更新界面(特别感谢@iparanoid提供主题设计) +* 升级jquery和angular版本 + +`2018-12-21` +* 修复虾米音乐歌单访问的问题 +* 修复网易云音乐歌单只有一首歌的问题 +* 修复bilibili滚动时加载重复歌单的问题 +* 修复酷狗部分音乐无法播放的问题 +* 修复Github Gist备份无法导入的问题 +* 升级soundmanager2库到最新版本 `2018-12-05` * 完全修复虾米音乐歌单访问的问题 @@ -166,11 +184,6 @@ Firefox打包安装 * 增加音量控制 -即将到来的功能 ----- - -* 歌单云同步(基于Gist) - License -------- diff --git a/app/listen1_chrome_extension/README_EN.md b/app/listen1_chrome_extension/README_EN.md new file mode 100644 index 0000000..7991552 --- /dev/null +++ b/app/listen1_chrome_extension/README_EN.md @@ -0,0 +1,56 @@ +Listen 1 (Chrome Extension) V2.1.0 +========== +(Last Update 12/24/2018) + +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE) + +One for all free music in China +---- +When I found many songs are unavailable because copyright issue, I realized there's something I should do. +Mom never need to worry about I can't listen my favorite songs. Listen 1 includes song libraries from Netease, QQ, Kugou, Kuwo, Bilibili. + +Search songs, listen songs from multiple platforms, that's `Listen 1`. + +Making your own playlist is also supported. + +How to change language ? +-------------------------- +1. Click Settings icon in right top of application +2. Click `English` under `Language` or `语言` + +Install (Chrome) +---- +1. download zip file from github and uncompress to local. + +2. open Extensions from chrome. + +3. Choose `Load unpacked`(Open Develop Mode first),Click folder you just uncompressed, finish! + +Install (Firefox) +----------- +1. Visit Listen1 Firefox Page https://addons.mozilla.org/zh-CN/firefox/addon/listen-1/ +2. Click Add to Firefox button + +Changelog +------- +`2018-12-24` +* i18n support, support English language. +* new song will now add to top of playlist +* copyright notification will not mess up the screen + +`2018-12-22` +* Version 2.0 released. New UI(Special Thanks to @iparanoid) +* Upgrade jquery, Angular + +`2018-12-21` +* Fix xiami playlist bug +* Fix netease playlist only shows one song bug +* Fix bilibili first load duplicate playlists +* Fix can't play some kugou songs +* Fix github gist backup recover bug +* Upgrade soundmanager2 + + +License +-------- +MIT diff --git a/app/listen1_chrome_extension/css/cover.css b/app/listen1_chrome_extension/css/cover.css index f6ddb76..1059298 100644 --- a/app/listen1_chrome_extension/css/cover.css +++ b/app/listen1_chrome_extension/css/cover.css @@ -2,10 +2,6 @@ * Globals */ -@font-face { - font-family: "Helvetica Neue", Helvetica, Arial, "Microsoft Yahei", "Hiragino Sans GB", "Heiti SC", "WenQuanYi Micro Hei", sans-serif; -} - /* Links */ @@ -24,7 +20,8 @@ a:hover { color: #333; text-shadow: none; /* Prevent inheritence from `body` */ - background-color: #fff; + background-color: rgba(255, 255, 255, 0.5); + /* background-color: #fff; */ border: 1px solid #fff; } @@ -36,19 +33,13 @@ a:hover { html, body { height: 100%; - font-size: 14px; - line-height: 1.5em; - font-family: "Helvetica Neue", Helvetica, Arial, "Microsoft Yahei", "Hiragino Sans GB", "Heiti SC", "WenQuanYi Micro Hei", sans-serif; /* background-color: #333; */ - /* background-color: transparent; */ - background-color: rgba(68, 68, 68, 0.3); + background-color: rgba(255, 255, 255, 0.5); } body { color: #fff; overflow: hidden !important; - /* background-color: transparent; */ - /* background-color: rgba(30, 30, 30, 0.5); */ /* text-align: center;*/ /*text-shadow: 0 1px 3px rgba(0,0,0,.5);*/ } @@ -62,21 +53,15 @@ body { height: 100%; /* For at least Firefox */ min-height: 100%; - -webkit-box-shadow: inset 0 0 600px rgba(0, 0, 0, .6); - box-shadow: inset 0 0 600px rgba(0, 0, 0, .6); + /* -webkit-box-shadow: inset 0 0 100px rgba(0,0,0,.5); + box-shadow: inset 0 0 100px rgba(0,0,0,.5);*/ } .site-wrapper-inner { display: table-cell; vertical-align: top; - /* background-color: rgba(68, 68, 68, 0.9) */ } - -/* .site-wrapper { - background-color: rgba(68, 68, 68, 0.9), -} */ - .cover-container { margin-right: auto; margin-left: auto; @@ -110,7 +95,7 @@ body { .masthead-nav>li>a { padding-right: 0; padding-left: 0; - font-size: 14px; + font-size: 16px; font-weight: bold; color: #fff; /* IE8 proofing */ @@ -118,12 +103,6 @@ body { border-bottom: 2px solid transparent; } - -/* .masthead-nav>li>a#minmin { - padding-right: 10px; - padding-left: 10px; -} */ - .masthead-nav>li>a:hover, .masthead-nav>li>a:focus { background-color: transparent; @@ -131,13 +110,6 @@ body { border-bottom-color: rgba(255, 255, 255, .25); } -.masthead-nav>li>a#minmin:hover, -.masthead-nav>li>a#minmin:focus { - background-color: rgba(255, 255, 255, .25); - /* border-bottom-color: #a9a9a9; */ - border-bottom-color: transparent; -} - .masthead-nav>.active>a, .masthead-nav>.active>a:hover, .masthead-nav>.active>a:focus { @@ -177,7 +149,6 @@ body { color: #999; /* IE8 proofing */ color: rgba(255, 255, 255, .5); - width: 100%; } @@ -212,7 +183,7 @@ body { .masthead, .mastfoot, .cover-container { - width: 100%; + width: 880px; } } diff --git a/app/listen1_chrome_extension/css/hover-min.css b/app/listen1_chrome_extension/css/hover-min.css new file mode 100644 index 0000000..9080816 --- /dev/null +++ b/app/listen1_chrome_extension/css/hover-min.css @@ -0,0 +1,9 @@ +/*! + * Hover.css (http://ianlunn.github.io/Hover/) + * Version: 2.3.2 + * Author: Ian Lunn @IanLunn + * Author URL: http://ianlunn.co.uk/ + * Github: https://github.com/IanLunn/Hover + + * Hover.css Copyright Ian Lunn 2017. Generated with Sass. + */.hvr-grow{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform}.hvr-grow:active,.hvr-grow:focus,.hvr-grow:hover{-webkit-transform:scale(1.1);transform:scale(1.1)}.hvr-shrink{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform}.hvr-shrink:active,.hvr-shrink:focus,.hvr-shrink:hover{-webkit-transform:scale(0.9);transform:scale(0.9)}@-webkit-keyframes hvr-pulse{25%{-webkit-transform:scale(1.1);transform:scale(1.1)}75%{-webkit-transform:scale(0.9);transform:scale(0.9)}}@keyframes hvr-pulse{25%{-webkit-transform:scale(1.1);transform:scale(1.1)}75%{-webkit-transform:scale(0.9);transform:scale(0.9)}}.hvr-pulse{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-pulse:active,.hvr-pulse:focus,.hvr-pulse:hover{-webkit-animation-name:hvr-pulse;animation-name:hvr-pulse;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}@-webkit-keyframes hvr-pulse-grow{to{-webkit-transform:scale(1.1);transform:scale(1.1)}}@keyframes hvr-pulse-grow{to{-webkit-transform:scale(1.1);transform:scale(1.1)}}.hvr-pulse-grow{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-pulse-grow:active,.hvr-pulse-grow:focus,.hvr-pulse-grow:hover{-webkit-animation-name:hvr-pulse-grow;animation-name:hvr-pulse-grow;-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-direction:alternate;animation-direction:alternate}@-webkit-keyframes hvr-pulse-shrink{to{-webkit-transform:scale(0.9);transform:scale(0.9)}}@keyframes hvr-pulse-shrink{to{-webkit-transform:scale(0.9);transform:scale(0.9)}}.hvr-pulse-shrink{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-pulse-shrink:active,.hvr-pulse-shrink:focus,.hvr-pulse-shrink:hover{-webkit-animation-name:hvr-pulse-shrink;animation-name:hvr-pulse-shrink;-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-direction:alternate;animation-direction:alternate}@-webkit-keyframes hvr-push{50%{-webkit-transform:scale(0.8);transform:scale(0.8)}100%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes hvr-push{50%{-webkit-transform:scale(0.8);transform:scale(0.8)}100%{-webkit-transform:scale(1);transform:scale(1)}}.hvr-push{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-push:active,.hvr-push:focus,.hvr-push:hover{-webkit-animation-name:hvr-push;animation-name:hvr-push;-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:1;animation-iteration-count:1}@-webkit-keyframes hvr-pop{50%{-webkit-transform:scale(1.2);transform:scale(1.2)}}@keyframes hvr-pop{50%{-webkit-transform:scale(1.2);transform:scale(1.2)}}.hvr-pop{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-pop:active,.hvr-pop:focus,.hvr-pop:hover{-webkit-animation-name:hvr-pop;animation-name:hvr-pop;-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:1;animation-iteration-count:1}.hvr-bounce-in{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.5s;transition-duration:.5s}.hvr-bounce-in:active,.hvr-bounce-in:focus,.hvr-bounce-in:hover{-webkit-transform:scale(1.2);transform:scale(1.2);-webkit-transition-timing-function:cubic-bezier(0.47,2.02,.31,-.36);transition-timing-function:cubic-bezier(0.47,2.02,.31,-.36)}.hvr-bounce-out{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.5s;transition-duration:.5s}.hvr-bounce-out:active,.hvr-bounce-out:focus,.hvr-bounce-out:hover{-webkit-transform:scale(0.8);transform:scale(0.8);-webkit-transition-timing-function:cubic-bezier(0.47,2.02,.31,-.36);transition-timing-function:cubic-bezier(0.47,2.02,.31,-.36)}.hvr-rotate{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform}.hvr-rotate:active,.hvr-rotate:focus,.hvr-rotate:hover{-webkit-transform:rotate(4deg);transform:rotate(4deg)}.hvr-grow-rotate{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform}.hvr-grow-rotate:active,.hvr-grow-rotate:focus,.hvr-grow-rotate:hover{-webkit-transform:scale(1.1) rotate(4deg);transform:scale(1.1) rotate(4deg)}.hvr-float{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-float:active,.hvr-float:focus,.hvr-float:hover{-webkit-transform:translateY(-8px);transform:translateY(-8px)}.hvr-sink{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-sink:active,.hvr-sink:focus,.hvr-sink:hover{-webkit-transform:translateY(8px);transform:translateY(8px)}@-webkit-keyframes hvr-bob{0%{-webkit-transform:translateY(-8px);transform:translateY(-8px)}50%{-webkit-transform:translateY(-4px);transform:translateY(-4px)}100%{-webkit-transform:translateY(-8px);transform:translateY(-8px)}}@keyframes hvr-bob{0%{-webkit-transform:translateY(-8px);transform:translateY(-8px)}50%{-webkit-transform:translateY(-4px);transform:translateY(-4px)}100%{-webkit-transform:translateY(-8px);transform:translateY(-8px)}}@-webkit-keyframes hvr-bob-float{100%{-webkit-transform:translateY(-8px);transform:translateY(-8px)}}@keyframes hvr-bob-float{100%{-webkit-transform:translateY(-8px);transform:translateY(-8px)}}.hvr-bob{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-bob:active,.hvr-bob:focus,.hvr-bob:hover{-webkit-animation-name:hvr-bob-float,hvr-bob;animation-name:hvr-bob-float,hvr-bob;-webkit-animation-duration:.3s,1.5s;animation-duration:.3s,1.5s;-webkit-animation-delay:0s,.3s;animation-delay:0s,.3s;-webkit-animation-timing-function:ease-out,ease-in-out;animation-timing-function:ease-out,ease-in-out;-webkit-animation-iteration-count:1,infinite;animation-iteration-count:1,infinite;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-direction:normal,alternate;animation-direction:normal,alternate}@-webkit-keyframes hvr-hang{0%{-webkit-transform:translateY(8px);transform:translateY(8px)}50%{-webkit-transform:translateY(4px);transform:translateY(4px)}100%{-webkit-transform:translateY(8px);transform:translateY(8px)}}@keyframes hvr-hang{0%{-webkit-transform:translateY(8px);transform:translateY(8px)}50%{-webkit-transform:translateY(4px);transform:translateY(4px)}100%{-webkit-transform:translateY(8px);transform:translateY(8px)}}@-webkit-keyframes hvr-hang-sink{100%{-webkit-transform:translateY(8px);transform:translateY(8px)}}@keyframes hvr-hang-sink{100%{-webkit-transform:translateY(8px);transform:translateY(8px)}}.hvr-hang{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-hang:active,.hvr-hang:focus,.hvr-hang:hover{-webkit-animation-name:hvr-hang-sink,hvr-hang;animation-name:hvr-hang-sink,hvr-hang;-webkit-animation-duration:.3s,1.5s;animation-duration:.3s,1.5s;-webkit-animation-delay:0s,.3s;animation-delay:0s,.3s;-webkit-animation-timing-function:ease-out,ease-in-out;animation-timing-function:ease-out,ease-in-out;-webkit-animation-iteration-count:1,infinite;animation-iteration-count:1,infinite;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-direction:normal,alternate;animation-direction:normal,alternate}.hvr-skew{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform}.hvr-skew:active,.hvr-skew:focus,.hvr-skew:hover{-webkit-transform:skew(-10deg);transform:skew(-10deg)}.hvr-skew-forward{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform;-webkit-transform-origin:0 100%;transform-origin:0 100%}.hvr-skew-forward:active,.hvr-skew-forward:focus,.hvr-skew-forward:hover{-webkit-transform:skew(-10deg);transform:skew(-10deg)}.hvr-skew-backward{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform;-webkit-transform-origin:0 100%;transform-origin:0 100%}.hvr-skew-backward:active,.hvr-skew-backward:focus,.hvr-skew-backward:hover{-webkit-transform:skew(10deg);transform:skew(10deg)}@-webkit-keyframes hvr-wobble-vertical{16.65%{-webkit-transform:translateY(8px);transform:translateY(8px)}33.3%{-webkit-transform:translateY(-6px);transform:translateY(-6px)}49.95%{-webkit-transform:translateY(4px);transform:translateY(4px)}66.6%{-webkit-transform:translateY(-2px);transform:translateY(-2px)}83.25%{-webkit-transform:translateY(1px);transform:translateY(1px)}100%{-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes hvr-wobble-vertical{16.65%{-webkit-transform:translateY(8px);transform:translateY(8px)}33.3%{-webkit-transform:translateY(-6px);transform:translateY(-6px)}49.95%{-webkit-transform:translateY(4px);transform:translateY(4px)}66.6%{-webkit-transform:translateY(-2px);transform:translateY(-2px)}83.25%{-webkit-transform:translateY(1px);transform:translateY(1px)}100%{-webkit-transform:translateY(0);transform:translateY(0)}}.hvr-wobble-vertical{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-wobble-vertical:active,.hvr-wobble-vertical:focus,.hvr-wobble-vertical:hover{-webkit-animation-name:hvr-wobble-vertical;animation-name:hvr-wobble-vertical;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-iteration-count:1;animation-iteration-count:1}@-webkit-keyframes hvr-wobble-horizontal{16.65%{-webkit-transform:translateX(8px);transform:translateX(8px)}33.3%{-webkit-transform:translateX(-6px);transform:translateX(-6px)}49.95%{-webkit-transform:translateX(4px);transform:translateX(4px)}66.6%{-webkit-transform:translateX(-2px);transform:translateX(-2px)}83.25%{-webkit-transform:translateX(1px);transform:translateX(1px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes hvr-wobble-horizontal{16.65%{-webkit-transform:translateX(8px);transform:translateX(8px)}33.3%{-webkit-transform:translateX(-6px);transform:translateX(-6px)}49.95%{-webkit-transform:translateX(4px);transform:translateX(4px)}66.6%{-webkit-transform:translateX(-2px);transform:translateX(-2px)}83.25%{-webkit-transform:translateX(1px);transform:translateX(1px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}.hvr-wobble-horizontal{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-wobble-horizontal:active,.hvr-wobble-horizontal:focus,.hvr-wobble-horizontal:hover{-webkit-animation-name:hvr-wobble-horizontal;animation-name:hvr-wobble-horizontal;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-iteration-count:1;animation-iteration-count:1}@-webkit-keyframes hvr-wobble-to-bottom-right{16.65%{-webkit-transform:translate(8px,8px);transform:translate(8px,8px)}33.3%{-webkit-transform:translate(-6px,-6px);transform:translate(-6px,-6px)}49.95%{-webkit-transform:translate(4px,4px);transform:translate(4px,4px)}66.6%{-webkit-transform:translate(-2px,-2px);transform:translate(-2px,-2px)}83.25%{-webkit-transform:translate(1px,1px);transform:translate(1px,1px)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes hvr-wobble-to-bottom-right{16.65%{-webkit-transform:translate(8px,8px);transform:translate(8px,8px)}33.3%{-webkit-transform:translate(-6px,-6px);transform:translate(-6px,-6px)}49.95%{-webkit-transform:translate(4px,4px);transform:translate(4px,4px)}66.6%{-webkit-transform:translate(-2px,-2px);transform:translate(-2px,-2px)}83.25%{-webkit-transform:translate(1px,1px);transform:translate(1px,1px)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}.hvr-wobble-to-bottom-right{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-wobble-to-bottom-right:active,.hvr-wobble-to-bottom-right:focus,.hvr-wobble-to-bottom-right:hover{-webkit-animation-name:hvr-wobble-to-bottom-right;animation-name:hvr-wobble-to-bottom-right;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-iteration-count:1;animation-iteration-count:1}@-webkit-keyframes hvr-wobble-to-top-right{16.65%{-webkit-transform:translate(8px,-8px);transform:translate(8px,-8px)}33.3%{-webkit-transform:translate(-6px,6px);transform:translate(-6px,6px)}49.95%{-webkit-transform:translate(4px,-4px);transform:translate(4px,-4px)}66.6%{-webkit-transform:translate(-2px,2px);transform:translate(-2px,2px)}83.25%{-webkit-transform:translate(1px,-1px);transform:translate(1px,-1px)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes hvr-wobble-to-top-right{16.65%{-webkit-transform:translate(8px,-8px);transform:translate(8px,-8px)}33.3%{-webkit-transform:translate(-6px,6px);transform:translate(-6px,6px)}49.95%{-webkit-transform:translate(4px,-4px);transform:translate(4px,-4px)}66.6%{-webkit-transform:translate(-2px,2px);transform:translate(-2px,2px)}83.25%{-webkit-transform:translate(1px,-1px);transform:translate(1px,-1px)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}.hvr-wobble-to-top-right{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-wobble-to-top-right:active,.hvr-wobble-to-top-right:focus,.hvr-wobble-to-top-right:hover{-webkit-animation-name:hvr-wobble-to-top-right;animation-name:hvr-wobble-to-top-right;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-iteration-count:1;animation-iteration-count:1}@-webkit-keyframes hvr-wobble-top{16.65%{-webkit-transform:skew(-12deg);transform:skew(-12deg)}33.3%{-webkit-transform:skew(10deg);transform:skew(10deg)}49.95%{-webkit-transform:skew(-6deg);transform:skew(-6deg)}66.6%{-webkit-transform:skew(4deg);transform:skew(4deg)}83.25%{-webkit-transform:skew(-2deg);transform:skew(-2deg)}100%{-webkit-transform:skew(0);transform:skew(0)}}@keyframes hvr-wobble-top{16.65%{-webkit-transform:skew(-12deg);transform:skew(-12deg)}33.3%{-webkit-transform:skew(10deg);transform:skew(10deg)}49.95%{-webkit-transform:skew(-6deg);transform:skew(-6deg)}66.6%{-webkit-transform:skew(4deg);transform:skew(4deg)}83.25%{-webkit-transform:skew(-2deg);transform:skew(-2deg)}100%{-webkit-transform:skew(0);transform:skew(0)}}.hvr-wobble-top{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transform-origin:0 100%;transform-origin:0 100%}.hvr-wobble-top:active,.hvr-wobble-top:focus,.hvr-wobble-top:hover{-webkit-animation-name:hvr-wobble-top;animation-name:hvr-wobble-top;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-iteration-count:1;animation-iteration-count:1}@-webkit-keyframes hvr-wobble-bottom{16.65%{-webkit-transform:skew(-12deg);transform:skew(-12deg)}33.3%{-webkit-transform:skew(10deg);transform:skew(10deg)}49.95%{-webkit-transform:skew(-6deg);transform:skew(-6deg)}66.6%{-webkit-transform:skew(4deg);transform:skew(4deg)}83.25%{-webkit-transform:skew(-2deg);transform:skew(-2deg)}100%{-webkit-transform:skew(0);transform:skew(0)}}@keyframes hvr-wobble-bottom{16.65%{-webkit-transform:skew(-12deg);transform:skew(-12deg)}33.3%{-webkit-transform:skew(10deg);transform:skew(10deg)}49.95%{-webkit-transform:skew(-6deg);transform:skew(-6deg)}66.6%{-webkit-transform:skew(4deg);transform:skew(4deg)}83.25%{-webkit-transform:skew(-2deg);transform:skew(-2deg)}100%{-webkit-transform:skew(0);transform:skew(0)}}.hvr-wobble-bottom{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transform-origin:100% 0;transform-origin:100% 0}.hvr-wobble-bottom:active,.hvr-wobble-bottom:focus,.hvr-wobble-bottom:hover{-webkit-animation-name:hvr-wobble-bottom;animation-name:hvr-wobble-bottom;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-iteration-count:1;animation-iteration-count:1}@-webkit-keyframes hvr-wobble-skew{16.65%{-webkit-transform:skew(-12deg);transform:skew(-12deg)}33.3%{-webkit-transform:skew(10deg);transform:skew(10deg)}49.95%{-webkit-transform:skew(-6deg);transform:skew(-6deg)}66.6%{-webkit-transform:skew(4deg);transform:skew(4deg)}83.25%{-webkit-transform:skew(-2deg);transform:skew(-2deg)}100%{-webkit-transform:skew(0);transform:skew(0)}}@keyframes hvr-wobble-skew{16.65%{-webkit-transform:skew(-12deg);transform:skew(-12deg)}33.3%{-webkit-transform:skew(10deg);transform:skew(10deg)}49.95%{-webkit-transform:skew(-6deg);transform:skew(-6deg)}66.6%{-webkit-transform:skew(4deg);transform:skew(4deg)}83.25%{-webkit-transform:skew(-2deg);transform:skew(-2deg)}100%{-webkit-transform:skew(0);transform:skew(0)}}.hvr-wobble-skew{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-wobble-skew:active,.hvr-wobble-skew:focus,.hvr-wobble-skew:hover{-webkit-animation-name:hvr-wobble-skew;animation-name:hvr-wobble-skew;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-iteration-count:1;animation-iteration-count:1}@-webkit-keyframes hvr-buzz{50%{-webkit-transform:translateX(3px) rotate(2deg);transform:translateX(3px) rotate(2deg)}100%{-webkit-transform:translateX(-3px) rotate(-2deg);transform:translateX(-3px) rotate(-2deg)}}@keyframes hvr-buzz{50%{-webkit-transform:translateX(3px) rotate(2deg);transform:translateX(3px) rotate(2deg)}100%{-webkit-transform:translateX(-3px) rotate(-2deg);transform:translateX(-3px) rotate(-2deg)}}.hvr-buzz{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-buzz:active,.hvr-buzz:focus,.hvr-buzz:hover{-webkit-animation-name:hvr-buzz;animation-name:hvr-buzz;-webkit-animation-duration:.15s;animation-duration:.15s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}@-webkit-keyframes hvr-buzz-out{10%{-webkit-transform:translateX(3px) rotate(2deg);transform:translateX(3px) rotate(2deg)}20%{-webkit-transform:translateX(-3px) rotate(-2deg);transform:translateX(-3px) rotate(-2deg)}30%{-webkit-transform:translateX(3px) rotate(2deg);transform:translateX(3px) rotate(2deg)}40%{-webkit-transform:translateX(-3px) rotate(-2deg);transform:translateX(-3px) rotate(-2deg)}50%{-webkit-transform:translateX(2px) rotate(1deg);transform:translateX(2px) rotate(1deg)}60%{-webkit-transform:translateX(-2px) rotate(-1deg);transform:translateX(-2px) rotate(-1deg)}70%{-webkit-transform:translateX(2px) rotate(1deg);transform:translateX(2px) rotate(1deg)}80%{-webkit-transform:translateX(-2px) rotate(-1deg);transform:translateX(-2px) rotate(-1deg)}90%{-webkit-transform:translateX(1px) rotate(0);transform:translateX(1px) rotate(0)}100%{-webkit-transform:translateX(-1px) rotate(0);transform:translateX(-1px) rotate(0)}}@keyframes hvr-buzz-out{10%{-webkit-transform:translateX(3px) rotate(2deg);transform:translateX(3px) rotate(2deg)}20%{-webkit-transform:translateX(-3px) rotate(-2deg);transform:translateX(-3px) rotate(-2deg)}30%{-webkit-transform:translateX(3px) rotate(2deg);transform:translateX(3px) rotate(2deg)}40%{-webkit-transform:translateX(-3px) rotate(-2deg);transform:translateX(-3px) rotate(-2deg)}50%{-webkit-transform:translateX(2px) rotate(1deg);transform:translateX(2px) rotate(1deg)}60%{-webkit-transform:translateX(-2px) rotate(-1deg);transform:translateX(-2px) rotate(-1deg)}70%{-webkit-transform:translateX(2px) rotate(1deg);transform:translateX(2px) rotate(1deg)}80%{-webkit-transform:translateX(-2px) rotate(-1deg);transform:translateX(-2px) rotate(-1deg)}90%{-webkit-transform:translateX(1px) rotate(0);transform:translateX(1px) rotate(0)}100%{-webkit-transform:translateX(-1px) rotate(0);transform:translateX(-1px) rotate(0)}}.hvr-buzz-out{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-buzz-out:active,.hvr-buzz-out:focus,.hvr-buzz-out:hover{-webkit-animation-name:hvr-buzz-out;animation-name:hvr-buzz-out;-webkit-animation-duration:.75s;animation-duration:.75s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:1;animation-iteration-count:1}.hvr-forward{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform}.hvr-forward:active,.hvr-forward:focus,.hvr-forward:hover{-webkit-transform:translateX(8px);transform:translateX(8px)}.hvr-backward{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform}.hvr-backward:active,.hvr-backward:focus,.hvr-backward:hover{-webkit-transform:translateX(-8px);transform:translateX(-8px)}.hvr-fade{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);overflow:hidden;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:color,background-color;transition-property:color,background-color}.hvr-fade:active,.hvr-fade:focus,.hvr-fade:hover{background-color:#2098D1;color:#fff}@-webkit-keyframes hvr-back-pulse{50%{background-color:rgba(32,152,209,.75)}}@keyframes hvr-back-pulse{50%{background-color:rgba(32,152,209,.75)}}.hvr-back-pulse{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);overflow:hidden;-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:color,background-color;transition-property:color,background-color}.hvr-back-pulse:active,.hvr-back-pulse:focus,.hvr-back-pulse:hover{-webkit-animation-name:hvr-back-pulse;animation-name:hvr-back-pulse;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-delay:.5s;animation-delay:.5s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;background-color:#2098D1;background-color:#2098d1;color:#fff}.hvr-sweep-to-right{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;-webkit-transition-property:color;transition-property:color;-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-sweep-to-right:before{content:"";position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;background:#2098D1;-webkit-transform:scaleX(0);transform:scaleX(0);-webkit-transform-origin:0 50%;transform-origin:0 50%;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-sweep-to-right:active,.hvr-sweep-to-right:focus,.hvr-sweep-to-right:hover{color:#fff}.hvr-sweep-to-right:active:before,.hvr-sweep-to-right:focus:before,.hvr-sweep-to-right:hover:before{-webkit-transform:scaleX(1);transform:scaleX(1)}.hvr-sweep-to-left{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;-webkit-transition-property:color;transition-property:color;-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-sweep-to-left:before{content:"";position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;background:#2098D1;-webkit-transform:scaleX(0);transform:scaleX(0);-webkit-transform-origin:100% 50%;transform-origin:100% 50%;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-sweep-to-left:active,.hvr-sweep-to-left:focus,.hvr-sweep-to-left:hover{color:#fff}.hvr-sweep-to-left:active:before,.hvr-sweep-to-left:focus:before,.hvr-sweep-to-left:hover:before{-webkit-transform:scaleX(1);transform:scaleX(1)}.hvr-sweep-to-bottom{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;-webkit-transition-property:color;transition-property:color;-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-sweep-to-bottom:before{content:"";position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;background:#2098D1;-webkit-transform:scaleY(0);transform:scaleY(0);-webkit-transform-origin:50% 0;transform-origin:50% 0;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-sweep-to-bottom:active,.hvr-sweep-to-bottom:focus,.hvr-sweep-to-bottom:hover{color:#fff}.hvr-sweep-to-bottom:active:before,.hvr-sweep-to-bottom:focus:before,.hvr-sweep-to-bottom:hover:before{-webkit-transform:scaleY(1);transform:scaleY(1)}.hvr-sweep-to-top{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;-webkit-transition-property:color;transition-property:color;-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-sweep-to-top:before{content:"";position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;background:#2098D1;-webkit-transform:scaleY(0);transform:scaleY(0);-webkit-transform-origin:50% 100%;transform-origin:50% 100%;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-sweep-to-top:active,.hvr-sweep-to-top:focus,.hvr-sweep-to-top:hover{color:#fff}.hvr-sweep-to-top:active:before,.hvr-sweep-to-top:focus:before,.hvr-sweep-to-top:hover:before{-webkit-transform:scaleY(1);transform:scaleY(1)}.hvr-bounce-to-right{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;-webkit-transition-property:color;transition-property:color;-webkit-transition-duration:.5s;transition-duration:.5s}.hvr-bounce-to-right:before{content:"";position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;background:#2098D1;-webkit-transform:scaleX(0);transform:scaleX(0);-webkit-transform-origin:0 50%;transform-origin:0 50%;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-bounce-to-right:active,.hvr-bounce-to-right:focus,.hvr-bounce-to-right:hover{color:#fff}.hvr-bounce-to-right:active:before,.hvr-bounce-to-right:focus:before,.hvr-bounce-to-right:hover:before{-webkit-transform:scaleX(1);transform:scaleX(1);-webkit-transition-timing-function:cubic-bezier(0.52,1.64,.37,.66);transition-timing-function:cubic-bezier(0.52,1.64,.37,.66)}.hvr-bounce-to-left{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;-webkit-transition-property:color;transition-property:color;-webkit-transition-duration:.5s;transition-duration:.5s}.hvr-bounce-to-left:before{content:"";position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;background:#2098D1;-webkit-transform:scaleX(0);transform:scaleX(0);-webkit-transform-origin:100% 50%;transform-origin:100% 50%;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-bounce-to-left:active,.hvr-bounce-to-left:focus,.hvr-bounce-to-left:hover{color:#fff}.hvr-bounce-to-left:active:before,.hvr-bounce-to-left:focus:before,.hvr-bounce-to-left:hover:before{-webkit-transform:scaleX(1);transform:scaleX(1);-webkit-transition-timing-function:cubic-bezier(0.52,1.64,.37,.66);transition-timing-function:cubic-bezier(0.52,1.64,.37,.66)}.hvr-bounce-to-bottom{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;-webkit-transition-property:color;transition-property:color;-webkit-transition-duration:.5s;transition-duration:.5s}.hvr-bounce-to-bottom:before{content:"";position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;background:#2098D1;-webkit-transform:scaleY(0);transform:scaleY(0);-webkit-transform-origin:50% 0;transform-origin:50% 0;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-bounce-to-bottom:active,.hvr-bounce-to-bottom:focus,.hvr-bounce-to-bottom:hover{color:#fff}.hvr-bounce-to-bottom:active:before,.hvr-bounce-to-bottom:focus:before,.hvr-bounce-to-bottom:hover:before{-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition-timing-function:cubic-bezier(0.52,1.64,.37,.66);transition-timing-function:cubic-bezier(0.52,1.64,.37,.66)}.hvr-bounce-to-top{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;-webkit-transition-property:color;transition-property:color;-webkit-transition-duration:.5s;transition-duration:.5s}.hvr-bounce-to-top:before{content:"";position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;background:#2098D1;-webkit-transform:scaleY(0);transform:scaleY(0);-webkit-transform-origin:50% 100%;transform-origin:50% 100%;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-bounce-to-top:active,.hvr-bounce-to-top:focus,.hvr-bounce-to-top:hover{color:#fff}.hvr-bounce-to-top:active:before,.hvr-bounce-to-top:focus:before,.hvr-bounce-to-top:hover:before{-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition-timing-function:cubic-bezier(0.52,1.64,.37,.66);transition-timing-function:cubic-bezier(0.52,1.64,.37,.66)}.hvr-radial-out{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;overflow:hidden;background:#e1e1e1;-webkit-transition-property:color;transition-property:color;-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-radial-out:before{content:"";position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;background:#2098D1;border-radius:100%;-webkit-transform:scale(0);transform:scale(0);-webkit-transition-property:transform;transition-property:transform;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-radial-out:active,.hvr-radial-out:focus,.hvr-radial-out:hover{color:#fff}.hvr-radial-out:active:before,.hvr-radial-out:focus:before,.hvr-radial-out:hover:before{-webkit-transform:scale(2);transform:scale(2)}.hvr-radial-in{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;overflow:hidden;background:#2098D1;-webkit-transition-property:color;transition-property:color;-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-radial-in:before{content:"";position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;background:#e1e1e1;border-radius:100%;-webkit-transform:scale(2);transform:scale(2);-webkit-transition-property:transform;transition-property:transform;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-radial-in:active,.hvr-radial-in:focus,.hvr-radial-in:hover{color:#fff}.hvr-radial-in:active:before,.hvr-radial-in:focus:before,.hvr-radial-in:hover:before{-webkit-transform:scale(0);transform:scale(0)}.hvr-rectangle-in{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;background:#2098D1;-webkit-transition-property:color;transition-property:color;-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-rectangle-in:before{content:"";position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;background:#e1e1e1;-webkit-transform:scale(1);transform:scale(1);-webkit-transition-property:transform;transition-property:transform;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-rectangle-in:active,.hvr-rectangle-in:focus,.hvr-rectangle-in:hover{color:#fff}.hvr-rectangle-in:active:before,.hvr-rectangle-in:focus:before,.hvr-rectangle-in:hover:before{-webkit-transform:scale(0);transform:scale(0)}.hvr-rectangle-out{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;background:#e1e1e1;-webkit-transition-property:color;transition-property:color;-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-rectangle-out:before{content:"";position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;background:#2098D1;-webkit-transform:scale(0);transform:scale(0);-webkit-transition-property:transform;transition-property:transform;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-rectangle-out:active,.hvr-rectangle-out:focus,.hvr-rectangle-out:hover{color:#fff}.hvr-rectangle-out:active:before,.hvr-rectangle-out:focus:before,.hvr-rectangle-out:hover:before{-webkit-transform:scale(1);transform:scale(1)}.hvr-shutter-in-horizontal{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;background:#2098D1;-webkit-transition-property:color;transition-property:color;-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-shutter-in-horizontal:before{content:"";position:absolute;z-index:-1;top:0;bottom:0;left:0;right:0;background:#e1e1e1;-webkit-transform:scaleX(1);transform:scaleX(1);-webkit-transform-origin:50%;transform-origin:50%;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-shutter-in-horizontal:active,.hvr-shutter-in-horizontal:focus,.hvr-shutter-in-horizontal:hover{color:#fff}.hvr-shutter-in-horizontal:active:before,.hvr-shutter-in-horizontal:focus:before,.hvr-shutter-in-horizontal:hover:before{-webkit-transform:scaleX(0);transform:scaleX(0)}.hvr-shutter-out-horizontal{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;background:#e1e1e1;-webkit-transition-property:color;transition-property:color;-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-shutter-out-horizontal:before{content:"";position:absolute;z-index:-1;top:0;bottom:0;left:0;right:0;background:#2098D1;-webkit-transform:scaleX(0);transform:scaleX(0);-webkit-transform-origin:50%;transform-origin:50%;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-shutter-out-horizontal:active,.hvr-shutter-out-horizontal:focus,.hvr-shutter-out-horizontal:hover{color:#fff}.hvr-shutter-out-horizontal:active:before,.hvr-shutter-out-horizontal:focus:before,.hvr-shutter-out-horizontal:hover:before{-webkit-transform:scaleX(1);transform:scaleX(1)}.hvr-shutter-in-vertical{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;background:#2098D1;-webkit-transition-property:color;transition-property:color;-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-shutter-in-vertical:before{content:"";position:absolute;z-index:-1;top:0;bottom:0;left:0;right:0;background:#e1e1e1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transform-origin:50%;transform-origin:50%;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-shutter-in-vertical:active,.hvr-shutter-in-vertical:focus,.hvr-shutter-in-vertical:hover{color:#fff}.hvr-shutter-in-vertical:active:before,.hvr-shutter-in-vertical:focus:before,.hvr-shutter-in-vertical:hover:before{-webkit-transform:scaleY(0);transform:scaleY(0)}.hvr-shutter-out-vertical{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;background:#e1e1e1;-webkit-transition-property:color;transition-property:color;-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-shutter-out-vertical:before{content:"";position:absolute;z-index:-1;top:0;bottom:0;left:0;right:0;background:#2098D1;-webkit-transform:scaleY(0);transform:scaleY(0);-webkit-transform-origin:50%;transform-origin:50%;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-shutter-out-vertical:active,.hvr-shutter-out-vertical:focus,.hvr-shutter-out-vertical:hover{color:#fff}.hvr-shutter-out-vertical:active:before,.hvr-shutter-out-vertical:focus:before,.hvr-shutter-out-vertical:hover:before{-webkit-transform:scaleY(1);transform:scaleY(1)}.hvr-border-fade{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:box-shadow;transition-property:box-shadow;box-shadow:inset 0 0 0 4px #e1e1e1,0 0 1px rgba(0,0,0,0)}.hvr-border-fade:active,.hvr-border-fade:focus,.hvr-border-fade:hover{box-shadow:inset 0 0 0 4px #2098D1,0 0 1px rgba(0,0,0,0)}.hvr-hollow{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:background;transition-property:background;box-shadow:inset 0 0 0 4px #e1e1e1,0 0 1px rgba(0,0,0,0)}.hvr-hollow:active,.hvr-hollow:focus,.hvr-hollow:hover{background:0 0}.hvr-trim{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative}.hvr-trim:before{content:'';position:absolute;border:#fff solid 4px;top:4px;left:4px;right:4px;bottom:4px;opacity:0;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:opacity;transition-property:opacity}.hvr-trim:active:before,.hvr-trim:focus:before,.hvr-trim:hover:before{opacity:1}@-webkit-keyframes hvr-ripple-out{100%{top:-12px;right:-12px;bottom:-12px;left:-12px;opacity:0}}@keyframes hvr-ripple-out{100%{top:-12px;right:-12px;bottom:-12px;left:-12px;opacity:0}}.hvr-ripple-out{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative}.hvr-ripple-out:before{content:'';position:absolute;border:#e1e1e1 solid 6px;top:0;right:0;bottom:0;left:0;-webkit-animation-duration:1s;animation-duration:1s}.hvr-ripple-out:active:before,.hvr-ripple-out:focus:before,.hvr-ripple-out:hover:before{-webkit-animation-name:hvr-ripple-out;animation-name:hvr-ripple-out}@-webkit-keyframes hvr-ripple-in{100%{top:0;right:0;bottom:0;left:0;opacity:1}}@keyframes hvr-ripple-in{100%{top:0;right:0;bottom:0;left:0;opacity:1}}.hvr-ripple-in{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative}.hvr-ripple-in:before{content:'';position:absolute;border:#e1e1e1 solid 4px;top:-12px;right:-12px;bottom:-12px;left:-12px;opacity:0;-webkit-animation-duration:1s;animation-duration:1s}.hvr-ripple-in:active:before,.hvr-ripple-in:focus:before,.hvr-ripple-in:hover:before{-webkit-animation-name:hvr-ripple-in;animation-name:hvr-ripple-in}.hvr-outline-out{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative}.hvr-outline-out:before{content:'';position:absolute;border:#e1e1e1 solid 4px;top:0;right:0;bottom:0;left:0;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:top,right,bottom,left;transition-property:top,right,bottom,left}.hvr-outline-out:active:before,.hvr-outline-out:focus:before,.hvr-outline-out:hover:before{top:-8px;right:-8px;bottom:-8px;left:-8px}.hvr-outline-in{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative}.hvr-outline-in:before{pointer-events:none;content:'';position:absolute;border:#e1e1e1 solid 4px;top:-16px;right:-16px;bottom:-16px;left:-16px;opacity:0;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:top,right,bottom,left;transition-property:top,right,bottom,left}.hvr-outline-in:active:before,.hvr-outline-in:focus:before,.hvr-outline-in:hover:before{top:-8px;right:-8px;bottom:-8px;left:-8px;opacity:1}.hvr-round-corners{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:border-radius;transition-property:border-radius}.hvr-round-corners:active,.hvr-round-corners:focus,.hvr-round-corners:hover{border-radius:1em}.hvr-underline-from-left{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;overflow:hidden}.hvr-underline-from-left:before{content:"";position:absolute;z-index:-1;left:0;right:100%;bottom:0;background:#2098D1;height:4px;-webkit-transition-property:right;transition-property:right;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-underline-from-left:active:before,.hvr-underline-from-left:focus:before,.hvr-underline-from-left:hover:before{right:0}.hvr-underline-from-center{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;overflow:hidden}.hvr-underline-from-center:before{content:"";position:absolute;z-index:-1;left:51%;right:51%;bottom:0;background:#2098D1;height:4px;-webkit-transition-property:left,right;transition-property:left,right;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-underline-from-center:active:before,.hvr-underline-from-center:focus:before,.hvr-underline-from-center:hover:before{left:0;right:0}.hvr-underline-from-right{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;overflow:hidden}.hvr-underline-from-right:before{content:"";position:absolute;z-index:-1;left:100%;right:0;bottom:0;background:#2098D1;height:4px;-webkit-transition-property:left;transition-property:left;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-underline-from-right:active:before,.hvr-underline-from-right:focus:before,.hvr-underline-from-right:hover:before{left:0}.hvr-overline-from-left{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;overflow:hidden}.hvr-overline-from-left:before{content:"";position:absolute;z-index:-1;left:0;right:100%;top:0;background:#2098D1;height:4px;-webkit-transition-property:right;transition-property:right;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-overline-from-left:active:before,.hvr-overline-from-left:focus:before,.hvr-overline-from-left:hover:before{right:0}.hvr-overline-from-center{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;overflow:hidden}.hvr-overline-from-center:before{content:"";position:absolute;z-index:-1;left:51%;right:51%;top:0;background:#2098D1;height:4px;-webkit-transition-property:left,right;transition-property:left,right;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-overline-from-center:active:before,.hvr-overline-from-center:focus:before,.hvr-overline-from-center:hover:before{left:0;right:0}.hvr-overline-from-right{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;overflow:hidden}.hvr-overline-from-right:before{content:"";position:absolute;z-index:-1;left:100%;right:0;top:0;background:#2098D1;height:4px;-webkit-transition-property:left;transition-property:left;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-overline-from-right:active:before,.hvr-overline-from-right:focus:before,.hvr-overline-from-right:hover:before{left:0}.hvr-reveal{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;overflow:hidden}.hvr-reveal:before{content:"";position:absolute;z-index:-1;left:0;right:0;top:0;bottom:0;border-color:#2098D1;border-style:solid;border-width:0;-webkit-transition-property:border-width;transition-property:border-width;-webkit-transition-duration:.1s;transition-duration:.1s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-reveal:active:before,.hvr-reveal:focus:before,.hvr-reveal:hover:before{-webkit-transform:translateY(0);transform:translateY(0);border-width:4px}.hvr-underline-reveal{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;overflow:hidden}.hvr-underline-reveal:before{content:"";position:absolute;z-index:-1;left:0;right:0;bottom:0;background:#2098D1;height:4px;-webkit-transform:translateY(4px);transform:translateY(4px);-webkit-transition-property:transform;transition-property:transform;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-underline-reveal:active:before,.hvr-underline-reveal:focus:before,.hvr-underline-reveal:hover:before{-webkit-transform:translateY(0);transform:translateY(0)}.hvr-overline-reveal{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;overflow:hidden}.hvr-overline-reveal:before{content:"";position:absolute;z-index:-1;left:0;right:0;top:0;background:#2098D1;height:4px;-webkit-transform:translateY(-4px);transform:translateY(-4px);-webkit-transition-property:transform;transition-property:transform;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-overline-reveal:active:before,.hvr-overline-reveal:focus:before,.hvr-overline-reveal:hover:before{-webkit-transform:translateY(0);transform:translateY(0)}.hvr-glow{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:box-shadow;transition-property:box-shadow}.hvr-glow:active,.hvr-glow:focus,.hvr-glow:hover{box-shadow:0 0 8px rgba(0,0,0,.6)}.hvr-shadow{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:box-shadow;transition-property:box-shadow}.hvr-shadow:active,.hvr-shadow:focus,.hvr-shadow:hover{box-shadow:0 10px 10px -10px rgba(0,0,0,.5)}.hvr-grow-shadow{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:box-shadow,transform;transition-property:box-shadow,transform}.hvr-grow-shadow:active,.hvr-grow-shadow:focus,.hvr-grow-shadow:hover{box-shadow:0 10px 10px -10px rgba(0,0,0,.5);-webkit-transform:scale(1.1);transform:scale(1.1)}.hvr-box-shadow-outset{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:box-shadow;transition-property:box-shadow}.hvr-box-shadow-outset:active,.hvr-box-shadow-outset:focus,.hvr-box-shadow-outset:hover{box-shadow:2px 2px 2px rgba(0,0,0,.6)}.hvr-box-shadow-inset{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:box-shadow;transition-property:box-shadow;box-shadow:inset 0 0 0 rgba(0,0,0,.6),0 0 1px rgba(0,0,0,0)}.hvr-box-shadow-inset:active,.hvr-box-shadow-inset:focus,.hvr-box-shadow-inset:hover{box-shadow:inset 2px 2px 2px rgba(0,0,0,.6),0 0 1px rgba(0,0,0,0)}.hvr-float-shadow{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform}.hvr-float-shadow:before{pointer-events:none;position:absolute;z-index:-1;content:'';top:100%;left:5%;height:10px;width:90%;opacity:0;background:-webkit-radial-gradient(center,ellipse,rgba(0,0,0,.35) 0,rgba(0,0,0,0) 80%);background:radial-gradient(ellipse at center,rgba(0,0,0,.35) 0,rgba(0,0,0,0) 80%);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform,opacity;transition-property:transform,opacity}.hvr-float-shadow:active,.hvr-float-shadow:focus,.hvr-float-shadow:hover{-webkit-transform:translateY(-5px);transform:translateY(-5px)}.hvr-float-shadow:active:before,.hvr-float-shadow:focus:before,.hvr-float-shadow:hover:before{opacity:1;-webkit-transform:translateY(5px);transform:translateY(5px)}.hvr-shadow-radial{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative}.hvr-shadow-radial:after,.hvr-shadow-radial:before{pointer-events:none;position:absolute;content:'';left:0;width:100%;box-sizing:border-box;height:5px;opacity:0;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:opacity;transition-property:opacity}.hvr-shadow-radial:before{bottom:100%;background:-webkit-radial-gradient(50% 150%,ellipse,rgba(0,0,0,.6) 0,rgba(0,0,0,0) 80%);background:radial-gradient(ellipse at 50% 150%,rgba(0,0,0,.6) 0,rgba(0,0,0,0) 80%)}.hvr-shadow-radial:after{top:100%;background:-webkit-radial-gradient(50% -50%,ellipse,rgba(0,0,0,.6) 0,rgba(0,0,0,0) 80%);background:radial-gradient(ellipse at 50% -50%,rgba(0,0,0,.6) 0,rgba(0,0,0,0) 80%)}.hvr-shadow-radial:active:after,.hvr-shadow-radial:active:before,.hvr-shadow-radial:focus:after,.hvr-shadow-radial:focus:before,.hvr-shadow-radial:hover:after,.hvr-shadow-radial:hover:before{opacity:1}.hvr-bubble-top{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative}.hvr-bubble-top:before{pointer-events:none;position:absolute;z-index:-1;content:'';border-style:solid;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform;left:calc(50% - 10px);top:0;border-width:0 10px 10px;border-color:transparent transparent #e1e1e1}.hvr-bubble-top:active:before,.hvr-bubble-top:focus:before,.hvr-bubble-top:hover:before{-webkit-transform:translateY(-10px);transform:translateY(-10px)}.hvr-bubble-right{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative}.hvr-bubble-right:before{pointer-events:none;position:absolute;z-index:-1;content:'';border-style:solid;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform;top:calc(50% - 10px);right:0;border-width:10px 0 10px 10px;border-color:transparent transparent transparent #e1e1e1}.hvr-bubble-right:active:before,.hvr-bubble-right:focus:before,.hvr-bubble-right:hover:before{-webkit-transform:translateX(10px);transform:translateX(10px)}.hvr-bubble-bottom{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative}.hvr-bubble-bottom:before{pointer-events:none;position:absolute;z-index:-1;content:'';border-style:solid;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform;left:calc(50% - 10px);bottom:0;border-width:10px 10px 0;border-color:#e1e1e1 transparent transparent}.hvr-bubble-bottom:active:before,.hvr-bubble-bottom:focus:before,.hvr-bubble-bottom:hover:before{-webkit-transform:translateY(10px);transform:translateY(10px)}.hvr-bubble-left{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative}.hvr-bubble-left:before{pointer-events:none;position:absolute;z-index:-1;content:'';border-style:solid;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform;top:calc(50% - 10px);left:0;border-width:10px 10px 10px 0;border-color:transparent #e1e1e1 transparent transparent}.hvr-bubble-left:active:before,.hvr-bubble-left:focus:before,.hvr-bubble-left:hover:before{-webkit-transform:translateX(-10px);transform:translateX(-10px)}.hvr-bubble-float-top{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform}.hvr-bubble-float-top:before{position:absolute;z-index:-1;content:'';left:calc(50% - 10px);top:0;border-style:solid;border-width:0 10px 10px;border-color:transparent transparent #e1e1e1;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform}.hvr-bubble-float-top:active,.hvr-bubble-float-top:focus,.hvr-bubble-float-top:hover{-webkit-transform:translateY(10px);transform:translateY(10px)}.hvr-bubble-float-top:active:before,.hvr-bubble-float-top:focus:before,.hvr-bubble-float-top:hover:before{-webkit-transform:translateY(-10px);transform:translateY(-10px)}.hvr-bubble-float-right{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform}.hvr-bubble-float-right:before{position:absolute;z-index:-1;top:calc(50% - 10px);right:0;content:'';border-style:solid;border-width:10px 0 10px 10px;border-color:transparent transparent transparent #e1e1e1;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform}.hvr-bubble-float-right:active,.hvr-bubble-float-right:focus,.hvr-bubble-float-right:hover{-webkit-transform:translateX(-10px);transform:translateX(-10px)}.hvr-bubble-float-right:active:before,.hvr-bubble-float-right:focus:before,.hvr-bubble-float-right:hover:before{-webkit-transform:translateX(10px);transform:translateX(10px)}.hvr-bubble-float-bottom{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform}.hvr-bubble-float-bottom:before{position:absolute;z-index:-1;content:'';left:calc(50% - 10px);bottom:0;border-style:solid;border-width:10px 10px 0;border-color:#e1e1e1 transparent transparent;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform}.hvr-bubble-float-bottom:active,.hvr-bubble-float-bottom:focus,.hvr-bubble-float-bottom:hover{-webkit-transform:translateY(-10px);transform:translateY(-10px)}.hvr-bubble-float-bottom:active:before,.hvr-bubble-float-bottom:focus:before,.hvr-bubble-float-bottom:hover:before{-webkit-transform:translateY(10px);transform:translateY(10px)}.hvr-bubble-float-left{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform}.hvr-bubble-float-left:before{position:absolute;z-index:-1;content:'';top:calc(50% - 10px);left:0;border-style:solid;border-width:10px 10px 10px 0;border-color:transparent #e1e1e1 transparent transparent;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform}.hvr-bubble-float-left:active,.hvr-bubble-float-left:focus,.hvr-bubble-float-left:hover{-webkit-transform:translateX(10px);transform:translateX(10px)}.hvr-bubble-float-left:active:before,.hvr-bubble-float-left:focus:before,.hvr-bubble-float-left:hover:before{-webkit-transform:translateX(-10px);transform:translateX(-10px)}.hvr-icon-back{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.1s;transition-duration:.1s}.hvr-icon-back .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition-duration:.1s;transition-duration:.1s;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-icon-back:active .hvr-icon,.hvr-icon-back:focus .hvr-icon,.hvr-icon-back:hover .hvr-icon{-webkit-transform:translateX(-4px);transform:translateX(-4px)}.hvr-icon-forward{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.1s;transition-duration:.1s}.hvr-icon-forward .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition-duration:.1s;transition-duration:.1s;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-icon-forward:active .hvr-icon,.hvr-icon-forward:focus .hvr-icon,.hvr-icon-forward:hover .hvr-icon{-webkit-transform:translateX(4px);transform:translateX(4px)}@-webkit-keyframes hvr-icon-down{0%,100%,50%{-webkit-transform:translateY(0);transform:translateY(0)}25%,75%{-webkit-transform:translateY(6px);transform:translateY(6px)}}@keyframes hvr-icon-down{0%,100%,50%{-webkit-transform:translateY(0);transform:translateY(0)}25%,75%{-webkit-transform:translateY(6px);transform:translateY(6px)}}.hvr-icon-down{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-icon-down .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0)}.hvr-icon-down:active .hvr-icon,.hvr-icon-down:focus .hvr-icon,.hvr-icon-down:hover .hvr-icon{-webkit-animation-name:hvr-icon-down;animation-name:hvr-icon-down;-webkit-animation-duration:.75s;animation-duration:.75s;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}@-webkit-keyframes hvr-icon-up{0%,100%,50%{-webkit-transform:translateY(0);transform:translateY(0)}25%,75%{-webkit-transform:translateY(-6px);transform:translateY(-6px)}}@keyframes hvr-icon-up{0%,100%,50%{-webkit-transform:translateY(0);transform:translateY(0)}25%,75%{-webkit-transform:translateY(-6px);transform:translateY(-6px)}}.hvr-icon-up{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-icon-up .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0)}.hvr-icon-up:active .hvr-icon,.hvr-icon-up:focus .hvr-icon,.hvr-icon-up:hover .hvr-icon{-webkit-animation-name:hvr-icon-up;animation-name:hvr-icon-up;-webkit-animation-duration:.75s;animation-duration:.75s;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}.hvr-icon-spin{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-icon-spin .hvr-icon{-webkit-transition-duration:1s;transition-duration:1s;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-timing-function:ease-in-out;transition-timing-function:ease-in-out}.hvr-icon-spin:active .hvr-icon,.hvr-icon-spin:focus .hvr-icon,.hvr-icon-spin:hover .hvr-icon{-webkit-transform:rotate(360deg);transform:rotate(360deg)}@-webkit-keyframes hvr-icon-drop{0%{opacity:0}50%{opacity:0;-webkit-transform:translateY(-100%);transform:translateY(-100%)}100%,51%{opacity:1}}@keyframes hvr-icon-drop{0%{opacity:0}50%{opacity:0;-webkit-transform:translateY(-100%);transform:translateY(-100%)}100%,51%{opacity:1}}.hvr-icon-drop{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-icon-drop .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0)}.hvr-icon-drop:active .hvr-icon,.hvr-icon-drop:focus .hvr-icon,.hvr-icon-drop:hover .hvr-icon{opacity:0;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-animation-name:hvr-icon-drop;animation-name:hvr-icon-drop;-webkit-animation-duration:.5s;animation-duration:.5s;-webkit-animation-delay:.3s;animation-delay:.3s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:cubic-bezier(0.52,1.64,.37,.66);animation-timing-function:cubic-bezier(0.52,1.64,.37,.66)}.hvr-icon-fade{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-icon-fade .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:color;transition-property:color}.hvr-icon-fade:active .hvr-icon,.hvr-icon-fade:focus .hvr-icon,.hvr-icon-fade:hover .hvr-icon{color:#0F9E5E}@-webkit-keyframes hvr-icon-float-away{0%{opacity:1}100%{opacity:0;-webkit-transform:translateY(-1em);transform:translateY(-1em)}}@keyframes hvr-icon-float-away{0%{opacity:1}100%{opacity:0;-webkit-transform:translateY(-1em);transform:translateY(-1em)}}.hvr-icon-float-away{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-icon-float-away .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-animation-duration:.5s;animation-duration:.5s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.hvr-icon-float-away:active .hvr-icon,.hvr-icon-float-away:focus .hvr-icon,.hvr-icon-float-away:hover .hvr-icon{-webkit-animation-name:hvr-icon-float-away;animation-name:hvr-icon-float-away;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}@-webkit-keyframes hvr-icon-sink-away{0%{opacity:1}100%{opacity:0;-webkit-transform:translateY(1em);transform:translateY(1em)}}@keyframes hvr-icon-sink-away{0%{opacity:1}100%{opacity:0;-webkit-transform:translateY(1em);transform:translateY(1em)}}.hvr-icon-sink-away{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-icon-sink-away .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-animation-duration:.5s;animation-duration:.5s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.hvr-icon-sink-away:active .hvr-icon,.hvr-icon-sink-away:focus .hvr-icon,.hvr-icon-sink-away:hover .hvr-icon{-webkit-animation-name:hvr-icon-sink-away;animation-name:hvr-icon-sink-away;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}.hvr-icon-grow{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-icon-grow .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-icon-grow:active .hvr-icon,.hvr-icon-grow:focus .hvr-icon,.hvr-icon-grow:hover .hvr-icon{-webkit-transform:scale(1.3) translateZ(0);transform:scale(1.3) translateZ(0)}.hvr-icon-shrink{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-icon-shrink .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-icon-shrink:active .hvr-icon,.hvr-icon-shrink:focus .hvr-icon,.hvr-icon-shrink:hover .hvr-icon{-webkit-transform:scale(0.8);transform:scale(0.8)}@-webkit-keyframes hvr-icon-pulse{25%{-webkit-transform:scale(1.3);transform:scale(1.3)}75%{-webkit-transform:scale(0.8);transform:scale(0.8)}}@keyframes hvr-icon-pulse{25%{-webkit-transform:scale(1.3);transform:scale(1.3)}75%{-webkit-transform:scale(0.8);transform:scale(0.8)}}.hvr-icon-pulse{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-icon-pulse .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-icon-pulse:active .hvr-icon,.hvr-icon-pulse:focus .hvr-icon,.hvr-icon-pulse:hover .hvr-icon{-webkit-animation-name:hvr-icon-pulse;animation-name:hvr-icon-pulse;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}@-webkit-keyframes hvr-icon-pulse-grow{to{-webkit-transform:scale(1.3);transform:scale(1.3)}}@keyframes hvr-icon-pulse-grow{to{-webkit-transform:scale(1.3);transform:scale(1.3)}}.hvr-icon-pulse-grow{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-icon-pulse-grow .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-icon-pulse-grow:active .hvr-icon,.hvr-icon-pulse-grow:focus .hvr-icon,.hvr-icon-pulse-grow:hover .hvr-icon{-webkit-animation-name:hvr-icon-pulse-grow;animation-name:hvr-icon-pulse-grow;-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-direction:alternate;animation-direction:alternate}@-webkit-keyframes hvr-icon-pulse-shrink{to{-webkit-transform:scale(0.8);transform:scale(0.8)}}@keyframes hvr-icon-pulse-shrink{to{-webkit-transform:scale(0.8);transform:scale(0.8)}}.hvr-icon-pulse-shrink{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0)}.hvr-icon-pulse-shrink .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-icon-pulse-shrink:active .hvr-icon,.hvr-icon-pulse-shrink:focus .hvr-icon,.hvr-icon-pulse-shrink:hover .hvr-icon{-webkit-animation-name:hvr-icon-pulse-shrink;animation-name:hvr-icon-pulse-shrink;-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-direction:alternate;animation-direction:alternate}@-webkit-keyframes hvr-icon-push{50%{-webkit-transform:scale(0.5);transform:scale(0.5)}}@keyframes hvr-icon-push{50%{-webkit-transform:scale(0.5);transform:scale(0.5)}}.hvr-icon-push{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-icon-push .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-icon-push:active .hvr-icon,.hvr-icon-push:focus .hvr-icon,.hvr-icon-push:hover .hvr-icon{-webkit-animation-name:hvr-icon-push;animation-name:hvr-icon-push;-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:1;animation-iteration-count:1}@-webkit-keyframes hvr-icon-pop{50%{-webkit-transform:scale(1.5);transform:scale(1.5)}}@keyframes hvr-icon-pop{50%{-webkit-transform:scale(1.5);transform:scale(1.5)}}.hvr-icon-pop{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-icon-pop .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-icon-pop:active .hvr-icon,.hvr-icon-pop:focus .hvr-icon,.hvr-icon-pop:hover .hvr-icon{-webkit-animation-name:hvr-icon-pop;animation-name:hvr-icon-pop;-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:1;animation-iteration-count:1}.hvr-icon-bounce{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-icon-bounce .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-icon-bounce:active .hvr-icon,.hvr-icon-bounce:focus .hvr-icon,.hvr-icon-bounce:hover .hvr-icon{-webkit-transform:scale(1.5);transform:scale(1.5);-webkit-transition-timing-function:cubic-bezier(0.47,2.02,.31,-.36);transition-timing-function:cubic-bezier(0.47,2.02,.31,-.36)}.hvr-icon-rotate{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-icon-rotate .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-icon-rotate:active .hvr-icon,.hvr-icon-rotate:focus .hvr-icon,.hvr-icon-rotate:hover .hvr-icon{-webkit-transform:rotate(20deg);transform:rotate(20deg)}.hvr-icon-grow-rotate{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-icon-grow-rotate .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-icon-grow-rotate:active .hvr-icon,.hvr-icon-grow-rotate:focus .hvr-icon,.hvr-icon-grow-rotate:hover .hvr-icon{-webkit-transform:scale(1.5) rotate(12deg);transform:scale(1.5) rotate(12deg)}.hvr-icon-float{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-icon-float .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-icon-float:active .hvr-icon,.hvr-icon-float:focus .hvr-icon,.hvr-icon-float:hover .hvr-icon{-webkit-transform:translateY(-4px);transform:translateY(-4px)}.hvr-icon-sink{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-icon-sink .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:transform;transition-property:transform;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out}.hvr-icon-sink:active .hvr-icon,.hvr-icon-sink:focus .hvr-icon,.hvr-icon-sink:hover .hvr-icon{-webkit-transform:translateY(4px);transform:translateY(4px)}@-webkit-keyframes hvr-icon-bob{0%{-webkit-transform:translateY(-6px);transform:translateY(-6px)}50%{-webkit-transform:translateY(-2px);transform:translateY(-2px)}100%{-webkit-transform:translateY(-6px);transform:translateY(-6px)}}@keyframes hvr-icon-bob{0%{-webkit-transform:translateY(-6px);transform:translateY(-6px)}50%{-webkit-transform:translateY(-2px);transform:translateY(-2px)}100%{-webkit-transform:translateY(-6px);transform:translateY(-6px)}}@-webkit-keyframes hvr-icon-bob-float{100%{-webkit-transform:translateY(-6px);transform:translateY(-6px)}}@keyframes hvr-icon-bob-float{100%{-webkit-transform:translateY(-6px);transform:translateY(-6px)}}.hvr-icon-bob{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-icon-bob .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0)}.hvr-icon-bob:active .hvr-icon,.hvr-icon-bob:focus .hvr-icon,.hvr-icon-bob:hover .hvr-icon{-webkit-animation-name:hvr-icon-bob-float,hvr-icon-bob;animation-name:hvr-icon-bob-float,hvr-icon-bob;-webkit-animation-duration:.3s,1.5s;animation-duration:.3s,1.5s;-webkit-animation-delay:0s,.3s;animation-delay:0s,.3s;-webkit-animation-timing-function:ease-out,ease-in-out;animation-timing-function:ease-out,ease-in-out;-webkit-animation-iteration-count:1,infinite;animation-iteration-count:1,infinite;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-direction:normal,alternate;animation-direction:normal,alternate}@-webkit-keyframes hvr-icon-hang{0%{-webkit-transform:translateY(6px);transform:translateY(6px)}50%{-webkit-transform:translateY(2px);transform:translateY(2px)}100%{-webkit-transform:translateY(6px);transform:translateY(6px)}}@keyframes hvr-icon-hang{0%{-webkit-transform:translateY(6px);transform:translateY(6px)}50%{-webkit-transform:translateY(2px);transform:translateY(2px)}100%{-webkit-transform:translateY(6px);transform:translateY(6px)}}@-webkit-keyframes hvr-icon-hang-sink{100%{-webkit-transform:translateY(6px);transform:translateY(6px)}}@keyframes hvr-icon-hang-sink{100%{-webkit-transform:translateY(6px);transform:translateY(6px)}}.hvr-icon-hang{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-icon-hang .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0)}.hvr-icon-hang:active .hvr-icon,.hvr-icon-hang:focus .hvr-icon,.hvr-icon-hang:hover .hvr-icon{-webkit-animation-name:hvr-icon-hang-sink,hvr-icon-hang;animation-name:hvr-icon-hang-sink,hvr-icon-hang;-webkit-animation-duration:.3s,1.5s;animation-duration:.3s,1.5s;-webkit-animation-delay:0s,.3s;animation-delay:0s,.3s;-webkit-animation-timing-function:ease-out,ease-in-out;animation-timing-function:ease-out,ease-in-out;-webkit-animation-iteration-count:1,infinite;animation-iteration-count:1,infinite;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-direction:normal,alternate;animation-direction:normal,alternate}@-webkit-keyframes hvr-icon-wobble-horizontal{16.65%{-webkit-transform:translateX(6px);transform:translateX(6px)}33.3%{-webkit-transform:translateX(-5px);transform:translateX(-5px)}49.95%{-webkit-transform:translateX(4px);transform:translateX(4px)}66.6%{-webkit-transform:translateX(-2px);transform:translateX(-2px)}83.25%{-webkit-transform:translateX(1px);transform:translateX(1px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes hvr-icon-wobble-horizontal{16.65%{-webkit-transform:translateX(6px);transform:translateX(6px)}33.3%{-webkit-transform:translateX(-5px);transform:translateX(-5px)}49.95%{-webkit-transform:translateX(4px);transform:translateX(4px)}66.6%{-webkit-transform:translateX(-2px);transform:translateX(-2px)}83.25%{-webkit-transform:translateX(1px);transform:translateX(1px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}.hvr-icon-wobble-horizontal{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-icon-wobble-horizontal .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0)}.hvr-icon-wobble-horizontal:active .hvr-icon,.hvr-icon-wobble-horizontal:focus .hvr-icon,.hvr-icon-wobble-horizontal:hover .hvr-icon{-webkit-animation-name:hvr-icon-wobble-horizontal;animation-name:hvr-icon-wobble-horizontal;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-iteration-count:1;animation-iteration-count:1}@-webkit-keyframes hvr-icon-wobble-vertical{16.65%{-webkit-transform:translateY(6px);transform:translateY(6px)}33.3%{-webkit-transform:translateY(-5px);transform:translateY(-5px)}49.95%{-webkit-transform:translateY(4px);transform:translateY(4px)}66.6%{-webkit-transform:translateY(-2px);transform:translateY(-2px)}83.25%{-webkit-transform:translateY(1px);transform:translateY(1px)}100%{-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes hvr-icon-wobble-vertical{16.65%{-webkit-transform:translateY(6px);transform:translateY(6px)}33.3%{-webkit-transform:translateY(-5px);transform:translateY(-5px)}49.95%{-webkit-transform:translateY(4px);transform:translateY(4px)}66.6%{-webkit-transform:translateY(-2px);transform:translateY(-2px)}83.25%{-webkit-transform:translateY(1px);transform:translateY(1px)}100%{-webkit-transform:translateY(0);transform:translateY(0)}}.hvr-icon-wobble-vertical{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-icon-wobble-vertical .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0)}.hvr-icon-wobble-vertical:active .hvr-icon,.hvr-icon-wobble-vertical:focus .hvr-icon,.hvr-icon-wobble-vertical:hover .hvr-icon{-webkit-animation-name:hvr-icon-wobble-vertical;animation-name:hvr-icon-wobble-vertical;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-iteration-count:1;animation-iteration-count:1}@-webkit-keyframes hvr-icon-buzz{50%{-webkit-transform:translateX(3px) rotate(2deg);transform:translateX(3px) rotate(2deg)}100%{-webkit-transform:translateX(-3px) rotate(-2deg);transform:translateX(-3px) rotate(-2deg)}}@keyframes hvr-icon-buzz{50%{-webkit-transform:translateX(3px) rotate(2deg);transform:translateX(3px) rotate(2deg)}100%{-webkit-transform:translateX(-3px) rotate(-2deg);transform:translateX(-3px) rotate(-2deg)}}.hvr-icon-buzz{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-icon-buzz .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0)}.hvr-icon-buzz:active .hvr-icon,.hvr-icon-buzz:focus .hvr-icon,.hvr-icon-buzz:hover .hvr-icon{-webkit-animation-name:hvr-icon-buzz;animation-name:hvr-icon-buzz;-webkit-animation-duration:.15s;animation-duration:.15s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}@-webkit-keyframes hvr-icon-buzz-out{10%{-webkit-transform:translateX(3px) rotate(2deg);transform:translateX(3px) rotate(2deg)}20%{-webkit-transform:translateX(-3px) rotate(-2deg);transform:translateX(-3px) rotate(-2deg)}30%{-webkit-transform:translateX(3px) rotate(2deg);transform:translateX(3px) rotate(2deg)}40%{-webkit-transform:translateX(-3px) rotate(-2deg);transform:translateX(-3px) rotate(-2deg)}50%{-webkit-transform:translateX(2px) rotate(1deg);transform:translateX(2px) rotate(1deg)}60%{-webkit-transform:translateX(-2px) rotate(-1deg);transform:translateX(-2px) rotate(-1deg)}70%{-webkit-transform:translateX(2px) rotate(1deg);transform:translateX(2px) rotate(1deg)}80%{-webkit-transform:translateX(-2px) rotate(-1deg);transform:translateX(-2px) rotate(-1deg)}90%{-webkit-transform:translateX(1px) rotate(0);transform:translateX(1px) rotate(0)}100%{-webkit-transform:translateX(-1px) rotate(0);transform:translateX(-1px) rotate(0)}}@keyframes hvr-icon-buzz-out{10%{-webkit-transform:translateX(3px) rotate(2deg);transform:translateX(3px) rotate(2deg)}20%{-webkit-transform:translateX(-3px) rotate(-2deg);transform:translateX(-3px) rotate(-2deg)}30%{-webkit-transform:translateX(3px) rotate(2deg);transform:translateX(3px) rotate(2deg)}40%{-webkit-transform:translateX(-3px) rotate(-2deg);transform:translateX(-3px) rotate(-2deg)}50%{-webkit-transform:translateX(2px) rotate(1deg);transform:translateX(2px) rotate(1deg)}60%{-webkit-transform:translateX(-2px) rotate(-1deg);transform:translateX(-2px) rotate(-1deg)}70%{-webkit-transform:translateX(2px) rotate(1deg);transform:translateX(2px) rotate(1deg)}80%{-webkit-transform:translateX(-2px) rotate(-1deg);transform:translateX(-2px) rotate(-1deg)}90%{-webkit-transform:translateX(1px) rotate(0);transform:translateX(1px) rotate(0)}100%{-webkit-transform:translateX(-1px) rotate(0);transform:translateX(-1px) rotate(0)}}.hvr-icon-buzz-out{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);-webkit-transition-duration:.3s;transition-duration:.3s}.hvr-icon-buzz-out .hvr-icon{-webkit-transform:translateZ(0);transform:translateZ(0)}.hvr-icon-buzz-out:active .hvr-icon,.hvr-icon-buzz-out:focus .hvr-icon,.hvr-icon-buzz-out:hover .hvr-icon{-webkit-animation-name:hvr-icon-buzz-out;animation-name:hvr-icon-buzz-out;-webkit-animation-duration:.75s;animation-duration:.75s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:1;animation-iteration-count:1}.hvr-curl-top-left{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative}.hvr-curl-top-left:before{pointer-events:none;position:absolute;content:'';height:0;width:0;top:0;left:0;background:#fff;background:linear-gradient(135deg,#fff 45%,#aaa 50%,#ccc 56%,#fff 80%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#ffffff', endColorstr='#000000');z-index:1000;box-shadow:1px 1px 1px rgba(0,0,0,.4);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:width,height;transition-property:width,height}.hvr-curl-top-left:active:before,.hvr-curl-top-left:focus:before,.hvr-curl-top-left:hover:before{width:25px;height:25px}.hvr-curl-top-right{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative}.hvr-curl-top-right:before{pointer-events:none;position:absolute;content:'';height:0;width:0;top:0;right:0;background:#fff;background:linear-gradient(225deg,#fff 45%,#aaa 50%,#ccc 56%,#fff 80%);box-shadow:-1px 1px 1px rgba(0,0,0,.4);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:width,height;transition-property:width,height}.hvr-curl-top-right:active:before,.hvr-curl-top-right:focus:before,.hvr-curl-top-right:hover:before{width:25px;height:25px}.hvr-curl-bottom-right{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative}.hvr-curl-bottom-right:before{pointer-events:none;position:absolute;content:'';height:0;width:0;bottom:0;right:0;background:#fff;background:linear-gradient(315deg,#fff 45%,#aaa 50%,#ccc 56%,#fff 80%);box-shadow:-1px -1px 1px rgba(0,0,0,.4);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:width,height;transition-property:width,height}.hvr-curl-bottom-right:active:before,.hvr-curl-bottom-right:focus:before,.hvr-curl-bottom-right:hover:before{width:25px;height:25px}.hvr-curl-bottom-left{display:inline-block;vertical-align:middle;-webkit-transform:perspective(1px) translateZ(0);transform:perspective(1px) translateZ(0);box-shadow:0 0 1px rgba(0,0,0,0);position:relative}.hvr-curl-bottom-left:before{pointer-events:none;position:absolute;content:'';height:0;width:0;bottom:0;left:0;background:#fff;background:linear-gradient(45deg,#fff 45%,#aaa 50%,#ccc 56%,#fff 80%);box-shadow:1px -1px 1px rgba(0,0,0,.4);-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:width,height;transition-property:width,height}.hvr-curl-bottom-left:active:before,.hvr-curl-bottom-left:focus:before,.hvr-curl-bottom-left:hover:before{width:25px;height:25px} \ No newline at end of file diff --git a/app/listen1_chrome_extension/css/icon.css b/app/listen1_chrome_extension/css/icon.css new file mode 100644 index 0000000..c4350e0 --- /dev/null +++ b/app/listen1_chrome_extension/css/icon.css @@ -0,0 +1,89 @@ +@font-face { + font-family: 'listen1-icon'; + src: url('../fonts/listen1-icon.eot?4ftssm'); + src: url('../fonts/listen1-icon.eot?4ftssm#iefix') format('embedded-opentype'), + url('../fonts/listen1-icon.ttf?4ftssm') format('truetype'), + url('../fonts/listen1-icon.woff?4ftssm') format('woff'), + url('../fonts/listen1-icon.svg?4ftssm#listen1-icon') format('svg'); + font-weight: normal; + font-style: normal; +} + +[class^="li-"], [class*=" li-"] { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: 'listen1-icon' !important; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.li-play:before { + content: "\e900"; +} +.li-previous:before { + content: "\e901"; +} +.li-next:before { + content: "\e902"; +} +.li-pause:before { + content: "\e903"; +} +.li-random-loop:before { + content: "\e904"; +} +.li-single-cycle:before { + content: "\e905"; +} +.li-mute:before { + content: "\e906"; +} +.li-volume:before { + content: "\e907"; +} +.li-list:before { + content: "\e908"; +} +.li-loop:before { + content: "\e909"; +} +.li-del:before { + content: "\e90a"; +} +.li-close:before { + content: "\e90b"; +} +.li-back:before { + content: "\e90c"; +} +.li-play-s:before { + content: "\e90d"; +} +.li-collapse:before { + content: "\e90e"; +} +.li-add:before { + content: "\e90f"; +} +.li-advance:before { + content: "\e910"; +} +.li-link:before { + content: "\e911"; +} +.li-setting:before { + content: "\e912"; +} +.li-songlist:before { + content: "\e913"; +} +.li-featured-list:before { + content: "\e914"; +} diff --git a/app/listen1_chrome_extension/css/iparanoid.css b/app/listen1_chrome_extension/css/iparanoid.css new file mode 100644 index 0000000..e9b8736 --- /dev/null +++ b/app/listen1_chrome_extension/css/iparanoid.css @@ -0,0 +1,1345 @@ +/* global settings (theme related) */ + +:root { + --icon-default-color: #666666; + --icon-highlight-color: #111111; + --text-default-color: #111111; + --text-subtitle-color: #666666; + --text-disable-color: #999999; + --lyric-default-color: #666666; + --link-default-color: #999999; + --link-highlight-color: #111111; + --line-default-color: #e5e5e5; + --sidebar-background-color: rgba(245, 245, 245, 0.7); + --content-background-color: #ffffff; + --foot-background-color: #ffffff; + --search-input-background-color: #f2f2f2; + --window-control-border-color: #dddddd; + --sidebar-highlight-background-color: #4d4d4d; + --sidebar-highlight-text-color: #ffffff; + --important-color: #ff4444; + --button-border-color: rga(255, 255, 255, 0); + --button-hover-background-color: #eeeeee; + --now-playing-page-background-color: rgba(255, 255, 255, 1); + --now-playing-close-icon-color: #666666; + --disable-song-title-color: #b7b7b7; + --windows-border-color: #dddddd; + --default-border-radius: 2px; + --text-default-size: 13px; + --h2-title-font-size: 24px; +} + +html, +body { + margin: 0; + padding: 0; + font-size: var(--text-default-size); + color: var(--text-default-color); + font-family: system-ui, "PingFang SC", STHeiti, sans-serif; +} + +.wrap { + /* border-style: solid; + border-color: rgba(255, 255, 255, 0.8); + border-width: 1px; */ + box-sizing: border-box; + /* border-radius: 5px; */ +} + + +/* remove focus highlight */ + +input:focus, +select:focus, +textarea:focus, +button:focus { + outline: none; +} + +ul { + list-style: none; + margin: 0; + padding: 0; +} + +input, +svg, +.icon { + -webkit-app-region: no-drag; +} + +svg { + width: 24px; + height: 24px; + stroke: currentColor; + stroke-width: 1; + stroke-linecap: round; + stroke-linejoin: round; + fill: none; + cursor: pointer; + /* stroke: var(--icon-default-color);*/ +} + +svg:hover { + /* fill: var(--icon-highlight-color);*/ + stroke: var(--icon-highlight-color); +} + +.icon { + /* default icon settings */ + font-size: 16px; + cursor: pointer; +} + + +/* tools utils */ + +.flex-scroll-wrapper { + flex: 1; + height: 100px; + overflow-y: scroll; +} + + +/* scroll bar style */ + +::-webkit-scrollbar { + width: 14px; + height: 18px; + background: transparent; +} + +::-webkit-scrollbar-thumb { + height: 49px; + border: 5px solid rgba(0, 0, 0, 0); + background-clip: padding-box; + -webkit-border-radius: 7px; + background-color: #c2c2c2; + /*rgba(151, 151, 151, 0.4);*/ + /* -webkit-box-shadow: inset -1px -1px 0px rgba(0, 0, 0, 0.05), inset 1px 1px 0px rgba(0, 0, 0, 0.05);*/ +} + +::-webkit-scrollbar-button { + width: 0; + height: 0; + display: none; +} + +::-webkit-scrollbar-corner { + background-color: transparent; +} + + +/* main framework start */ + +.wrap { + display: flex; + min-height: 100vh; + flex-direction: column; + margin: auto; +} + + +/* split screen to up/down 2 parts */ + +.main { + flex: 1; + display: flex; +} + +.footer { + background: rgba(255, 255, 255, 0.8); + height: 60px; + /* border-top: solid 1px var(--line-default-color); */ + display: flex; + position: relative; +} + + +/* split main to left/right 2 parts */ + +.main .sidebar { + flex: 0 0 200px; + display: flex; + flex-direction: column; + background: var(--sidebar-background-color); +} + +.main .content { + background: rgba(255, 255, 255, 0.8); + flex: 1; + display: flex; + flex-direction: column; +} + + +/* split content to up/down 2 parts */ + +.main .content .navigation { + height: 46px; + flex: 0 0 46px; + /* border-bottom: solid 1px var(--line-default-color); */ + display: flex; + align-items: center; + -webkit-app-region: drag; +} + +.main .content .browser { + flex: 1; +} + + +/* main framework end */ + + +/*****************************************************************/ + + +/* main sidebar start */ + +.sidebar .menu-control { + height: 43px; + width: 125px; + -webkit-app-region: drag; +} + +.sidebar .menu-title { + height: 28px; + line-height: 28px; + margin: 0 12px 4px 12px; + color: var(--link-default-color); + padding-left: 10px; + display: flex; + align-items: center; + font-size: 12px; +} + +.sidebar .menu-title .title { + flex: 1; +} + +.sidebar .menu-title svg { + flex: 0 0 18px; +} + +.sidebar ul li { + display: flex; + align-items: center; + line-height: 28px; + margin: 0 0 6px 12px; + color: var(--text-default-color); + cursor: pointer; + border-radius: var(--default-border-radius); + padding-left: 10px; +} + +.sidebar svg { + width: 18px; + height: 18px; +} + +.sidebar ul li a { + margin-left: 10px; + width: 125px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.sidebar ul li.active { + background: var(--sidebar-highlight-background-color); + color: var(--sidebar-highlight-text-color); +} + + +/* main sidebar end */ + + +/* widget navigation start */ + +.navigation svg { + width: 18px; + height: 18px; + color: var(--icon-default-color); +} + +.navigation .backfront { + flex: 0 0 45px; + line-height: 46px; + vertical-align: middle; + padding: 0 13px; +} + +.navigation .search { + flex: 1; +} + +.navigation .settings { + flex: 0 0 32px; +} + +.navigation .icon { + color: var(--text-default-color); + opacity: 0.5; +} + +.navigation .icon:hover { + opacity: 1; +} + +.navigation .backfront .icon { + display: inline-block; + vertical-align: middle; + margin-bottom: 4px; +} + +.navigation .backfront .icon:nth-of-type(1) { + margin-right: 8px; +} + +.navigation .search-input { + width: 270px; + height: 23px; + background: var(--search-input-background-color); + border-style: none; + border-radius: var(--default-border-radius); + padding-left: 10px; + font-size: 12px; +} + +.navigation .window-control { + flex: 0 0 105px; + border-left: solid 1px var(--window-control-border-color); + margin-left: 15px; +} + +.navigation .window-control svg { + margin-left: 8px; +} + +.navigation .window-control svg:first-of-type { + margin-left: 15px; +} + + +/* navigation end */ + + +/* page hot-playlist start */ + +.page-hot-playlist { + max-width: 850px; + margin: 0 auto; +} + +.playlist-covers { + margin: 0; + padding: 0 13px; + display: flex; + flex-flow: row wrap; + position: relative; +} + +.playlist-covers li { + flex: 0 1 calc(20% - 26px); + height: 215px; + color: var(--text-default-color); + margin: 0 13px; +} + +.playlist-covers .u-cover { + position: relative; +} + +.playlist-covers .u-cover img { + max-width: 100%; + /* border: solid 1px var(--line-default-color); */ + margin-bottom: 2px; + cursor: pointer; +} + +.playlist-covers .u-cover .bottom { + position: absolute; + right: 5px; + bottom: 10px; + height: 30px; + width: 30px; + cursor: pointer; + opacity: 0; + transition: opacity 0.2s linear; +} + +.playlist-covers .u-cover:hover .bottom { + opacity: 1; +} + +.playlist-covers .u-cover .bottom svg { + height: 30px; + width: 30px; + fill: rgba(200, 200, 200, 0.5); + stroke-width: 1; + stroke: #ffffff; +} + +.playlist-covers .u-cover .bottom svg:hover { + fill: rgba(100, 100, 100, 0.5); +} + +.playlist-covers .desc { + cursor: pointer; +} + + +/* page hot-playlist end */ + + +/* page playlist-detail start */ + +.page .playlist-detail { + padding-bottom: 37px; +} + +.page .playlist-detail .detail-head { + display: flex; +} + +.page .playlist-detail .detail-head img { + height: 150px; + width: 150px; +} + +.page .playlist-detail .detail-head .detail-head-cover { + flex: 0 0 150px; + padding: 26px 26px 8px 26px; +} + +.page .playlist-detail .detail-head .detail-head-title { + flex: 1; +} + +.playlist-button-list { + display: flex; +} + +.playlist-button-list .playlist-button { + height: 26px; + border: solid 1px var(--button-border-color); + cursor: pointer; + border-radius: 2px; + display: flex; + margin-right: 20px; +} + +.playlist-button-list .playlist-button.playadd-button { + flex: 0 0 136px; +} + +.playlist-button-list .playlist-button .play-list { + flex: 1; + padding-left: 18px; + display: flex; + align-items: center; +} + +.playlist-button-list .playlist-button .play-list svg { + margin-right: 4px; +} + +.playlist-button-list .playlist-button.playadd-button .play-list svg { + width: 14px; + height: 14px; + flex: 0 0 14px; + margin-right: 4px; + stroke: var(--important-color); + fill: var(--important-color); +} + +.playlist-button-list .playlist-button .play-list .icon { + margin-right: 8px; +} + +.playlist-button-list .playlist-button.playadd-button .play-list .icon { + flex: 0 0 14px; + margin-right: 4px; + color: var(--important-color); +} + +.playlist-button-list .playlist-button.playadd-button .add-list { + flex: 0 0 26px; + height: 26px; + width: 26px; + border-left: solid 1px var(--button-border-color); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; +} + +.playlist-button-list .playlist-button .play-list:hover, +.playlist-button-list .playlist-button.playadd-button .add-list:hover { + background: var(--button-hover-background-color); +} + +.playlist-button-list .playlist-button.playadd-button .add-list svg { + width: 14px; + height: 14px; +} + +.playlist-button-list .playlist-button.clone-button, +.playlist-button-list .playlist-button.edit-button { + flex: 0 0 90px; +} + +.playlist-button-list .playlist-button.clone-button .play-list svg, +.playlist-button-list .playlist-button.edit-button .play-list svg { + width: 16px; + height: 16px; + flex: 0 0 16px; + margin-right: 8px; + stroke: rgb(102, 102, 102); +} + +.page .playlist-detail .detail-head .detail-head-title h2 { + font-size: var(--h2-title-font-size); +} + + +/* page playlist detail end */ + + +/* page song detail start */ + +.page .songdetail-wrapper { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 60px; + background: var(--now-playing-page-background-color); + overflow: hidden; + /* border: solid 1px var(--windows-border-color); */ + -webkit-app-region: drag; +} + +.page .songdetail-wrapper .close { + position: absolute; + top: 24px; + left: 24px; + height: 24px; + width: 24px; + cursor: pointer; + -webkit-app-region: no-drag; +} + +.page .songdetail-wrapper .close.mac { + top: 44px; +} + +.page .songdetail-wrapper .window-control { + position: absolute; + top: 24px; + left: 55px; + height: 24px; + cursor: pointer; + -webkit-app-region: no-drag; +} + +.page .songdetail-wrapper .window-control svg { + margin-left: 8px; + stroke: var(--now-playing-close-icon-color); +} + +.page .songdetail-wrapper .close svg { + stroke: var(--now-playing-close-icon-color); +} + +.page .playsong-detail { + max-width: 770px; + margin: 0 auto; + display: flex; + height: 100%; +} + +.page .playsong-detail .detail-head { + flex: 0 0 350px; + overflow: hidden; +} + +.page .playsong-detail .detail-head .detail-head-cover { + width: 250px; + height: 250px; + margin-top: 110px; +} + +.page .playsong-detail .detail-head img { + width: 250px; + height: 250px; +} + +.page .playsong-detail .detail-songinfo { + flex: 1; + margin-top: 80px; + display: flex; + flex-direction: column; + overflow: hidden; + -webkit-app-region: no-drag; +} + +.page .playsong-detail .detail-songinfo h2 { + font-size: var(--h2-title-font-size); + margin-top: 20px; + margin-bottom: 12px; + font-weight: 400; +} + +.page .playsong-detail .detail-songinfo .info { + border-bottom: solid 1px var(--line-default-color); + padding-bottom: 6px; + flex: 0 0 20px; + display: flex; +} + +.page .playsong-detail .detail-songinfo .info a { + cursor: pointer; +} + +.page .playsong-detail .detail-songinfo .info .singer { + flex: 1; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.page .playsong-detail .detail-songinfo .info .album { + flex: 2; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.page .playsong-detail .detail-songinfo .info span { + color: var(--lyric-default-color); +} + +.page .playsong-detail .detail-songinfo .lyric { + flex: 0 0 380px; + overflow-y: scroll; + color: var(--lyric-default-color); + font-size: 14px; +} + +.page .playsong-detail .detail-songinfo .lyric p { + margin: 10px 0; +} + +.page .playsong-detail .detail-songinfo .lyric p.highlight { + color: var(--important-color); +} + +ul.detail-songlist { + padding: 0 25px; +} + +ul.detail-songlist li { + display: flex; + border-bottom: solid 1px rgba(200, 200, 200, 0.5); + height: 37px; + align-items: center; + padding: 0 20px; +} + +ul.detail-songlist li a { + cursor: pointer; +} + +ul.detail-songlist li a.disabled { + color: var(--disable-song-title-color); +} + +ul.detail-songlist li.head { + height: 28px; + color: var(--text-disable-color); +} + +ul.detail-songlist li .title { + flex: 2; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + line-height: 17px; + max-height: 38px; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +ul.detail-songlist li .artist { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + line-height: 17px; + max-height: 38px; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +ul.detail-songlist li .album { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + line-height: 17px; + max-height: 38px; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +ul.detail-songlist li .tools { + flex: 0 0 110px; + display: flex; + align-items: center; +} + +ul.detail-songlist li .tools .icon { + height: 16px; + width: 16px; + color: #9d9d9d; + margin-top: 2px; + margin-right: 10px; +} + + +/* page song detail end */ + + +/* page setting start */ + +.page .settings-title { + border-bottom: solid 1px var(--line-default-color); + padding-bottom: 10px; + max-width: 800px; + margin: 0 25px; + font-size: 17px; + margin-bottom: 10px; +} + +.page .settings-title:first-of-type { + margin-top: 20px; +} + +.page .settings-content { + margin: 0 25px 25px 25px; +} + +.page .settings-content label.upload-button { + border: solid 1px #999; + padding: 2px 9px; + background: #eeeeee; + margin-right: 4px; +} + +.page .settings-content .shortcut { + display: flex; + margin-top: 10px; +} + +.page .settings-content .shortcut svg { + width: 18px; + height: 18px; + margin-right: 10px; +} + +.page .searchbox .search-pagination { + text-align: center; + padding: 15px; +} + + +/* page setting end */ + +.loading_bottom { + display: block; + width: 40px; + margin: 0 auto; +} + +svg.searchspinner { + width: 20px; + height: 20px; + vertical-align: top; + margin-left: 15px; +} + + +/* footer start */ + +.footer { + background: rgba(255, 255, 255, 0.8); + height: 60px; + /* border-top: solid 1px #e5e5e5; */ + display: flex; + position: relative; +} + +.footer .left-control { + background-color: rgba(255, 255, 255, 0.8); + flex: 0 0 300px; + display: flex; + align-items: center; +} + +.footer .left-control .icon { + font-size: 22px; + color: #b1b1b1; + margin: 0 13px; +} + +.footer .left-control .icon.play { + margin-right: 10px; +} + +.footer .left-control .icon:first-of-type { + margin-left: 42px; +} + +.footer .left-control .icon.play { + color: #666666; +} + +.footer .left-control .icon.play:hover { + color: #666666; +} + +.footer .main-info { + flex: 1; + background: rgba(245, 245, 245, 0.8); + display: flex; + overflow: hidden; +} + +.footer .main-info .logo-banner { + text-align: center; + flex: 1; + display: flex; + align-items: center; +} + +.footer .main-info .logo-banner svg.logo { + height: 48px; + width: 48px; + fill: #666666; + stroke: #666666; + margin: 0 auto; +} + +.footer .main-info .cover { + height: 60px; + width: 60px; + flex: 0 0 60px; + cursor: pointer; +} + +.footer .main-info .detail { + flex: 1; + position: relative; + overflow: hidden; +} + +.footer .main-info .detail .ctrl { + position: absolute; + right: 0px; + top: 4px; + padding-right: 6px; + /* background: #eeeeee; */ + background-color: rgba(245, 245, 245, 0.8); +} + +.footer .main-info .detail .ctrl:first-of-type .icon { + margin-right: 5px; +} + +.footer .main-info .detail .ctrl .icon { + color: var(--text-default-color); + opacity: 0.5; +} + +.footer .main-info .detail .ctrl .icon:hover { + opacity: 1; +} + +.footer .main-info .detail .title { + text-align: center; + font-size: 14px; + color: var(--text-default-color); + margin-top: 3px; + min-width: 0px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.footer .main-info .detail .more-info { + padding: 0 10px; + display: flex; + color: var(--text-subtitle-color); +} + +.footer .main-info .detail .more-info .singer { + flex: 1; + text-align: center; + font-size: 12px; + min-width: 0px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.footer .main-info .detail .more-info .singer a { + cursor: pointer; +} + +.footer .main-info .detail .more-info .current { + width: 50px; + font-size: 12px; +} + +.footer .main-info .detail .more-info .total { + width: 50px; + text-align: right; + font-size: 12px; +} + +.footer .main-info .detail .playbar { + width: 100%; +} + +.footer .main-info .detail .playbar .barbg { + margin: 8px 10px 0 10px; + height: 3px; + background: #e0e0e0; +} + +.footer .main-info .detail .playbar .barbg .cur { + height: 100%; + background: #666666; + position: relative; +} + +.footer .main-info .detail .playbar .barbg .cur .btn { + background: #111111; + height: 8px; + width: 2px; + position: absolute; + right: -2px; + top: -5px; +} + +.footer .menu { + flex: 1; + background: #ffffff; + /* border: solid 1px #e5e5e5; */ + border-radius: 3px; + position: absolute; + height: 370px; + top: -372px; + left: 300px; + right: 300px; + -webkit-app-region: no-drag; +} + +.footer .menu .menu-header { + height: 30px; + /* border-bottom: solid 1px #e7e7e7; */ + display: flex; + align-items: center; + color: #9e9e9e; + font-size: 12px; +} + +.footer .menu .menu-header .menu-title { + flex: 1; + padding: 20px; +} + +.footer .menu .menu-header .add-all { + border-right: solid 1px #e5e5e5; + flex: 0 0 93px; + display: flex; + align-items: center; +} + +.footer .menu .menu-header .remove-all { + margin-left: 10px; + flex: 0 0 55px; + display: flex; + align-items: center; +} + +.footer .menu .menu-header .close { + margin-left: 10px; + flex: 0 0 25px; + align-items: center; + cursor: pointer; +} + +.footer .menu .menu-header .add-all span, +.footer .menu .menu-header .remove-all span { + cursor: pointer; +} + +.footer .menu .menu-header .add-all .icon, +.footer .menu .menu-header .remove-all .icon { + margin-right: 7px; +} + +.footer .menu .menu-header .close svg { + margin-right: 3px; + height: 16px; + width: 16px; + cursor: pointer; +} + +.footer .menu ul.menu-list { + overflow-y: scroll; + height: 340px; + font-size: 12px; +} + +.footer .menu ul.menu-list li { + display: flex; + align-items: center; + height: 30px; + padding-right: 20px; +} + +.footer .menu ul.menu-list li.even { + background: #f7f7f7; +} + +.footer .menu ul.menu-list li:hover { + background: #e5e5e5; +} + +.footer .menu ul.menu-list li.playing { + color: var(--important-color); +} + +.footer .menu ul.menu-list li .song-status-icon { + flex: 0 0 20px; + width: 20px; + height: 30px; + text-align: center; + display: flex; + align-items: center; +} + +.footer .menu ul.menu-list li .song-status-icon svg { + width: 10px; + height: 10px; + fill: var(--important-color); + stroke: var(--important-color); + flex: 1; +} + +.footer .menu ul.menu-list li .song-title { + flex: 2; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.footer .menu ul.menu-list li .song-title a { + cursor: pointer; +} + +.footer .menu ul.menu-list li .song-singer { + flex: 1; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + cursor: pointer; +} + +.footer .menu ul.menu-list li .tools { + flex: 0 0 42px; + width: 42px; +} + +.footer .menu ul.menu-list li .tools .icon { + color: #666666; + cursor: pointer; + opacity: 0.5; +} + +.footer .menu ul.menu-list li .tools .icon:first-of-type { + margin-right: 5px; +} + +.footer .menu ul.menu-list li .tools .icon:hover { + opacity: 1; +} + +.footer .menu ul.menu-list li .song-time { + flex: 1; + text-align: right; +} + +.footer .right-control { + flex: 0 0 300px; + background: rgba(255, 255, 255, 0.8); + display: flex; + align-items: center; +} + +.footer .right-control .playlist-toggle { + margin-left: 29px; + cursor: pointer; +} + +.footer .right-control .playlist-toggle .icon { + color: #333333; +} + +.footer .right-control .playlist-toggle .icon:hover { + color: #000000; +} + +.footer .right-control .volume-ctrl { + flex: 1; + display: flex; +} + +.footer .right-control .volume-ctrl .icon { + flex: 0 0 24px; + color: #333333; + cursor: pointer; + margin-left: 21px; +} + +.footer .right-control .volume-ctrl .m-pbar { + flex: 1; +} + +.footer .right-control .volume-ctrl .barbg { + height: 3px; + /* background: #e0e0e0; */ + background-color: rgba(255, 255, 255, 0.8); + margin-top: 7px; + width: 140px; +} + +.footer .right-control .volume-ctrl .barbg .cur { + height: 100%; + background: #333333; + position: relative; +} + +.footer .right-control .volume-ctrl .barbg .cur .btn { + background: #ffffff; + height: 13px; + width: 13px; + border: solid 1px #e4e4e4; + border-radius: 13px; + position: absolute; + right: -13px; + top: -6px; +} + + +/* footer end */ + + +/* dialog start */ + +.dialog { + position: absolute; + top: 120px; + width: 285px; + height: 430px; + z-index: 10000; + overflow: hidden; + border-radius: 4px; + background-color: #fafafa; + color: #565656; + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} + +.dialog-header { + height: 30px; + font-size: 15px; + font-weight: bold; + text-align: left; + padding: 12px; +} + +.dialog-header .dialog-close { + float: right; + font-size: 26px; + cursor: pointer; + margin-top: -10px; +} + +.dialog-body { + width: 100%; + height: 370px; + overflow-y: auto; + background-color: #fafafa; +} + +.dialog .detail-songlist li:hover { + background-color: #e3e3e5; + cursor: pointer; +} + +.dialog-playlist, +.dialog-backuplist, +.dialog-merge-playlist { + padding-left: 0px; + text-align: left; +} + +.dialog-playlist li, +.dialog-backuplist li, +.dialog-merge-playlist li { + cursor: pointer; + height: 48px; + padding: 6px; +} + +.dialog-backuplist li { + height: 96px; + padding: 6px; +} + +.dialog-playlist li:hover, +.dialog-backuplist li:hover, +.dialog-merge-playlist li:hover { + background-color: #e3e3e5; +} + +.dialog-playlist li img, +.dialog-backuplist li img, +.dialog-merge-playlist li img { + float: left; + height: 48px; + width: 48px; +} + +.dialog-playlist li h2, +.dialog-backuplist li h2, +.dialog-merge-playlist li h2 { + margin-left: 58px; + font-size: 13px; + font-weight: inherit; +} + +.dialog-backuplist li h2 { + margin-top: 0; +} + +.dialog-newplaylist { + padding: 10px; +} + +.dialog-newplaylist input { + width: 260px; +} + +.dialog-newplaylist .confirm-button { + margin-left: 36px; + margin-right: 58px; + margin-top: 20px; +} + +.dialog-newbackup { + text-align: center; +} + +.dialog-newbackup .confirm-button { + margin-right: 12px; +} + +.dialog-editplaylist, +.dialog-open-url { + padding: 10px; +} + +.dialog-editplaylist input, +.dialog-open-url input { + width: 260px; +} + +.dialog-editplaylist label, +.dialog-open-url label { + display: block; + height: 30px; + line-height: 30px; +} + +.dialog-editplaylist .dialog-footer { + position: absolute; + bottom: 20px; +} + +.dialog-editplaylist .confirm-button, +.dialog-open-url .confirm-button { + margin-right: 26px; + margin-left: 61px; + margin-top: 20px; +} + +.dialog-connect-lastfm .buttons { + margin-top: 30px; +} + +.dialog-connect-lastfm .confirm-button { + margin-left: 40px; + margin-right: 48px; +} + + +/* dialog end */ + + +/* widget source-list start */ + +.source-list { + margin: 20px 26px 25px 26px; +} + +.source-list .source-button { + display: inline-block; + color: #a9a9a9; + cursor: pointer; + padding-bottom: 4px; +} + +.source-list .source-button.active { + color: #323232; + border-bottom: solid 1px #323232; +} + +.source-list .splitter { + display: inline-block; + background: #a9a9a9; + margin-top: 1px; + height: 12px; + width: 1px; + margin: 0 10px; +} + +.btn { + border: solid 1px #999; + padding: 0.2em; + background-color: #eeeeee; +} + + +/* .upload-button { + border: 0; + padding: 0.5em; + background-color: rgba(255, 255, 255, 0.5); +} */ + + +/* widget source-list end */ \ No newline at end of file diff --git a/app/listen1_chrome_extension/css/player.css b/app/listen1_chrome_extension/css/player.css index d8b1129..10d3cb0 100644 --- a/app/listen1_chrome_extension/css/player.css +++ b/app/listen1_chrome_extension/css/player.css @@ -1,10 +1,10 @@ a { - cursor: pointer; + cursor: pointer; } .shadow { position: fixed; - background: rgba(30, 30, 30, 0.9); + background: rgba(30,30,30,0.9); _position: absolute; z-index: 9999; top: 0; @@ -21,7 +21,7 @@ a { top: 120px; width: 480px; height: 420px; - z-index: 10000; + z-index:10000; overflow: hidden; border-radius: 4px 4px 4px 4px; padding: 20px; @@ -53,13 +53,11 @@ a { background-color: #333; } - /*.masthead { z-index: 999; }*/ -.masthead, -.mastfoot { +.masthead, .mastfoot { margin: 0 auto; left: 0; right: 0; @@ -68,9 +66,7 @@ a { } .masthead { - /* background-color: #333; */ - background-color: transparent; - /* background-color: rgba(30, 30, 30, 0.5); */ + background-color: #333; height: 90px; } @@ -78,20 +74,17 @@ a { float: left; height: 50px; width: 50px; - margin-left: 27px; margin-right: 20px; cursor: pointer; } .masthead .masthead-brand { - color: rgba(255, 255, 255, 1); + color: rgba(255,255,255, 1); cursor: pointer; } .cover-container { position: relative; - background-color: transparent; - /* background-color: rgba(30, 30, 30, 0.5); */ } .container-placeholder { @@ -99,8 +92,8 @@ a { } .site-wrapper { - width: 100%; - overflow: hidden; + width:100%; + overflow:hidden; position: absolute; padding-left: 17px; } @@ -110,34 +103,33 @@ a { margin-top: 90px; /* uncomment the line below will hide the scroll bar */ /*padding-right: 17px;*/ - box-sizing: content-box; - width: 100%; - /* background-color: #333; */ - /* background-color: rgba(30, 30, 30, 0.5); */ - background-color: transparent; + box-sizing:content-box; + width:100%; + background-color: #333; } .searchbox { - /* margin-top: 100px;*/ +/* margin-top: 100px;*/ } -.searchbox .nav { +.searchbox .nav{ margin-top: 12px; } -.searchbox .nav .searchspinner { +.searchbox .nav .searchspinner{ margin-top: 8px; height: 25px; } + .searchitem { height: 92px; } .searchitem img { float: left; - height: 90px; - width: 90px; + height:90px; + width:90px; } .searchitem div { @@ -180,12 +172,12 @@ a { } .playlist-covers .loading_bottom { - clear: both; - text-align: center; + clear:both; + text-align:center; } .playlist-covers .loading_bottom img { - height: 35px; + height:35px; } .u-cover .mask { @@ -224,19 +216,16 @@ a { width: 100%; height: 90px; margin: 0 auto; - background-color: rgba(0, 0, 0, 0.5) + background-color: #222222; } + .m-playbar .btns { width: 157px; padding: 27px 0 0 19px; } -.m-playbar .btns, -.m-playbar .head, -.m-playbar .play, -.m-playbar .volum, -.m-playbar .oper { +.m-playbar .btns, .m-playbar .head, .m-playbar .play, .m-playbar .volum, .m-playbar .oper { float: left; } @@ -250,9 +239,7 @@ a { background: url(../images/loading.gif); } -.m-pbar .barbg, -.m-pbar .cur, -.m-pbar .left { +.m-pbar .barbg, .m-pbar .cur, .m-pbar .left { background: url(../images/statbar.png) no-repeat 0 9999px; _background-image: url(../images/statbar.png); } @@ -273,39 +260,39 @@ a { text-indent: -9999px; } -.m-playbar .btns .previous { +.m-playbar .btns .previous{ background-position: -72px 0px; } -.m-playbar .btns .previous:hover { - background-position: -72px -36px; +.m-playbar .btns .previous:hover{ + background-position:-72px -36px; } -.m-playbar .btns .play { +.m-playbar .btns .play{ width: 36px; height: 36px; - margin-top: 0; + margin-top:0; background-position: 0px 0px; } -.m-playbar .btns .play:hover { +.m-playbar .btns .play:hover{ background-position: 0px -36px; } -.m-playbar .btns .pas { +.m-playbar .btns .pas{ background-position: -108px 0px; } -.m-playbar .btns .pas:hover { +.m-playbar .btns .pas:hover{ background-position: -108px -36px; } -.m-playbar .btns .next { +.m-playbar .btns .next{ /* pause icon distance adjust from 36 to 38 */ background-position: -38px 0px; } -.m-playbar .btns .next:hover { +.m-playbar .btns .next:hover{ background-position: -38px -36px; } @@ -314,8 +301,7 @@ a { margin: 10px 15px 0 0; } -.m-playbar .head, -.m-playbar .head img { +.m-playbar .head, .m-playbar .head img { width: 70px; height: 70px; } @@ -335,7 +321,7 @@ a { margin-right: 120px; } -.m-playbar .words .notextdeco { +.m-playbar .words .notextdeco{ text-decoration: none; } @@ -393,6 +379,7 @@ a { .m-pbar { position: relative; + } .m-pbar.play { @@ -409,9 +396,7 @@ a { margin-top: 0px; } -.m-pbar .barbg, -.m-pbar .cur, -.m-pbar .rdy { +.m-pbar .barbg, .m-pbar .cur, .m-pbar .rdy { height: 7px; } @@ -419,6 +404,7 @@ a { background-position: right 0; } + .m-pbar .cur { position: absolute; top: 0; @@ -454,8 +440,7 @@ a { color: #a1a1a1; } -em, -i { +em, i { font-style: normal; text-align: left; font-size: inherit; @@ -577,15 +562,15 @@ i { position: relative; } -.m-playbar .menu .lyric p { +.m-playbar .menu .lyric p{ min-height: 20px; } -.m-playbar .menu .lyric .placeholder { +.m-playbar .menu .lyric .placeholder{ height: 50px; } -.m-playbar .menu .lyric .highlight { +.m-playbar .menu .lyric .highlight{ font-size: 15px; color: #ffffff; } @@ -594,8 +579,7 @@ i { background-color: #555555; } -.m-playbar .menu li:hover, -.m-playbar .menu li:focus { +.m-playbar .menu li:hover, .m-playbar .menu li:focus { background-color: #999999; } @@ -641,16 +625,15 @@ li { color: #ffffff; cursor: pointer; vertical-align: middle; - display: inline-block; + display:inline-block; width: 60px; line-height: 20px; } -.menu-header a:hover small { +.menu-header a:hover small{ background-color: #ffffff; color: #333333; } - .menu .add-all { display: inline-block; position: absolute; @@ -658,6 +641,7 @@ li { top: 9px; } + .menu .remove-all { display: inline-block; position: absolute; @@ -665,8 +649,9 @@ li { top: 9px; } + .menu .close-popup { - float: right; + float:right; margin-right: 14px; font-size: 20px; text-decoration: none; @@ -714,9 +699,7 @@ li { text-align: center; } -.form-signin .form-control, -.form-signin .valid-img, -.form-signin .btn { +.form-signin .form-control, .form-signin .valid-img, .form-signin .btn { margin-top: 10px; } @@ -730,52 +713,28 @@ li { } .playlist-detail { - position: fixed; - left: -20px; - top: 0; - bottom: 0; - overflow-y: scroll; - overflow-x: hidden; - /* width: 100%; */ - padding-top: 100px; - padding-bottom: 100px; - padding-left: 36px; - /* position: relative; */ - /* display: inline-block; */ - /* position: fixed; */ - /* display: block; */ - /* left: 30; */ - /* top: 0; */ - /* padding-top: 90px; */ - /* padding-left: 50px; */ + position: absolute; text-align: left; - background-color: rgba(30, 30, 30, 0.8); - /* background-color: #333; */ - -webkit-box-shadow: 0 0 200 200px rgba(0, 0, 0, 0.9); - box-shadow: 0 0 200 200px rgba(0, 0, 0, 0.9); + background-color: #333; width: 100%; - /* overflow: visible; */ } .playlist-detail .detail-head { width: 200px; position: fixed; margin-bottom: 20px; - margin-left: 20px; - padding-left: 10px; } .playlist-detail .detail-head-cover { height: 180px; - /* width: 225px;*/ +/* width: 225px;*/ float: left; margin: 10px; - margin-top: 0; } .playlist-detail .detail-head-cover img { - max-width: 100%; - max-height: 100%; + max-width:100%; + max-height:100%; } .detail-head-title { @@ -845,28 +804,17 @@ li { background-position: -40px -204px; } -.playlist-detail .detail-head-title h2 { +.playlist-detail .detail-head-title h2{ font-size: 17px; margin-bottom: 35px; } .playlist-detail .detail-songlist { margin-left: 220px; - margin-top: 0px; + margin-top: 6px; margin-right: 14px; } -.playsong-detail { - position: fixed; - left: -20px; - top: 0px; - width: 100%; - padding-top: 120px; - background-color: rgba(30, 30, 30, 0.9); - -webkit-box-shadow: inset 0 0 600px rgba(0, 0, 0, 0.5); - box-shadow: inset 0 0 600px rgba(0, 0, 0, 0.5); -} - .playsong-detail .detail-head { width: 390px; position: fixed; @@ -876,7 +824,7 @@ li { .playsong-detail .detail-songinfo { padding-left: 440px; padding-right: 55px; -} +} .playsong-detail .detail-head .detail-head-cover { margin: 0 auto; @@ -890,7 +838,6 @@ li { .playsong-detail .detail-songinfo h2 { font-size: 22px; - margin-top: 0px; } .playsong-detail .detail-songinfo .info { @@ -898,20 +845,16 @@ li { margin-bottom: 5px; padding-bottom: 10px; } - -.playsong-detail .detail-songinfo .info span { +.playsong-detail .detail-songinfo .info span{ color: #9b9b9b; margin-right: 10px; } - .playsong-detail .detail-songinfo .info span.album { margin-left: 30px; } - .playsong-detail .lyric { - color: #999; - /* IE8 proofing */ - color: rgba(255, 255, 255, .5); + color: #999; /* IE8 proofing */ + color: rgba(255,255,255,.5); text-align: left; width: 100%; display: inline-block; @@ -921,22 +864,21 @@ li { font-size: 15px; } -.playsong-detail .lyric p { +.playsong-detail .lyric p{ min-height: 20px; } -.playsong-detail .lyric .placeholder { +.playsong-detail .lyric .placeholder{ height: 50px; } -.playsong-detail .lyric .highlight { +.playsong-detail .lyric .highlight{ color: #ffffff; } .detail-songlist { padding-left: 0px; text-align: left; - margin-top: -10px; } .detail-songlist li { @@ -944,7 +886,6 @@ li { width: 100%; display: block; padding: 10px; - /* padding-top: 10px; */ } .detail-songlist .col2 { @@ -984,35 +925,35 @@ li { cursor: pointer; } -.detail-songlist .detail-tools .detail-add-button { +.detail-songlist .detail-tools .detail-add-button{ background-position: 0px 0px; } -.detail-songlist .detail-tools .detail-fav-button { +.detail-songlist .detail-tools .detail-fav-button{ background-position: -25px 0px; } -.detail-songlist .detail-tools .detail-delete-button { +.detail-songlist .detail-tools .detail-delete-button{ background-position: -75px 0px; } -.detail-songlist .detail-tools .source-button { +.detail-songlist .detail-tools .source-button{ background-position: -100px 0px; } -.detail-songlist .detail-tools .detail-add-button:hover { +.detail-songlist .detail-tools .detail-add-button:hover{ background-position: 0px -25px; } -.detail-songlist .detail-tools .detail-fav-button:hover { +.detail-songlist .detail-tools .detail-fav-button:hover{ background-position: -25px -25px; } -.detail-songlist .detail-tools .detail-delete-button:hover { +.detail-songlist .detail-tools .detail-delete-button:hover{ background-position: -75px -25px; } -.detail-songlist .detail-tools .source-button:hover { +.detail-songlist .detail-tools .source-button:hover{ background-position: -100px -25px; } @@ -1021,17 +962,16 @@ li { display: inline-block; } -.detail-songlist .detail-artist a { +.detail-songlist .detail-artist a{ color: #777777; } .detail-songlist .odd { - background-color: rgba(30, 30, 30, 0.3); + background-color: #333; } -.detail-songlist .even, -.detail-songlist .detail-add { - background-color: rgba(30, 30, 30, 0.6); +.detail-songlist .even, .detail-songlist .detail-add{ + background-color: #2d2d2d; } .dialog .detail-songlist li:hover { @@ -1039,12 +979,11 @@ li { cursor: pointer; } - /*.playlist-detail .detail-songlist li:hover { background-color: #999999; }*/ -.playlist-detail .btn { +.playlist-detail .btn{ width: 88px; margin-top: 0; float: left; @@ -1087,11 +1026,12 @@ li { width: 100px; } -.dialog-playlist li h2 { +.dialog-playlist li h2{ margin-left: 125px; font-size: 17px; } + .dialog-backuplist { padding-left: 0px; text-align: left; @@ -1113,7 +1053,7 @@ li { width: 100px; } -.dialog-backuplist li h2 { +.dialog-backuplist li h2{ margin-top: 10px; margin-left: 125px; font-size: 15px; @@ -1140,12 +1080,12 @@ li { width: 100px; } -.dialog-merge-playlist li h2 { +.dialog-merge-playlist li h2{ margin-left: 125px; font-size: 17px; } -.dialog-newplaylist input { +.dialog-newplaylist input{ margin-bottom: 22px; } @@ -1167,8 +1107,7 @@ li { bottom: 20px; } -.dialog-editplaylist .confirm-button, -.dialog-open-url .confirm-button { +.dialog-editplaylist .confirm-button, .dialog-open-url .confirm-button { margin-right: 82px; margin-left: 93px; } @@ -1177,32 +1116,31 @@ li { margin-top: 30px; } -.dialog-connect-lastfm .confirm-button { +.dialog-connect-lastfm .confirm-button{ margin-left: 40px; margin-right: 48px; } .source-list { position: absolute; - right: -0px; + right: -32px; top: 0px; z-index: 10; text-align: center; } -.source-list div { - background-color: rgba(30, 30, 30, 0.1); +.source-list div{ + background-color: #333333; color: #ffffff; height: 35px; - border: 0px solid #ffffff; + border: 1px solid #ffffff; width: 75px; cursor: pointer; vertical-align: middle; padding-top: 6px; } - -/* .source-list div:first-child:not(:last-child) { +.source-list div:first-child:not(:last-child) { border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 0; @@ -1214,15 +1152,15 @@ li { border-top-right-radius: 0; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; -} */ +} .source-list .active { - background-color: rgba(255, 255, 255, 0.9); - color: #333; + background-color: #e6e6e6; + color: #333333; } .source-list div:hover { - background-color: rgba(255, 255, 255, 0.9); + background-color: #ffffff; color: #333333; } @@ -1238,28 +1176,26 @@ li { .settings-content { padding: 20px; + } .settings-content .btn { margin-right: 10px; } -.btn-group button, -.btn-pagination, -.btn-pagination:focus { +.btn-group button,.btn-pagination,.btn-pagination:focus { background-color: #333333; color: #ffffff; border-color: #333333; } -.btn-group button:hover, -.btn-pagination:hover { +.btn-group button:hover,.btn-pagination:hover { background-color: #ffffff; color: #333333; } -.searchbox li>a:hover { - color: #333333; +.searchbox li>a:hover{ +color: #333333; } .search-pagination { @@ -1270,9 +1206,9 @@ li { } .search-pagination button:focus { - outline: 0; + outline:0; } .search-pagination label { margin: 0 15px; -} \ No newline at end of file +} diff --git a/app/listen1_chrome_extension/fonts/listen1-icon.eot b/app/listen1_chrome_extension/fonts/listen1-icon.eot new file mode 100644 index 0000000000000000000000000000000000000000..cf4b5a41ab3db1c8c1a640da70b41d0031356e42 GIT binary patch literal 3644 zcma)9Z)_CD6@RmHzQupfm%H;qxsW@bee1J*XZ!BfYrx?e#ai z=h)_7nB6z~-kUcwZ|1#uZ>O`0=!ca=j3ioH7+qw7)7QV2FJzr^d+@8ehuetO(=nQ) z6EsWXG)-+32Q^Ar;6zpQGPo0T5;7xn9Gn^&0OvU5CvBM!dL*b7El(Q<%|eNCGKo{` z-hC}e&vR}SoIe3Fqf;X@%D}CkLnsLPm5GrPGx%167T=&@tj(UF=%>pz47eW24*Bd2F5 zME#&m(4py(sqyjO{BkGgdCc+NO!mYq^hBu~6Ya$L61zwxMAFZskHER$eA!(}u~H$o zsxYX%wirZ9ex57j$lw4pE*nJ1g+yh~CT0wx&G~X$Do8Hs0KbgZ!Qc{jp(TGIUnq!9 zz{$p0;h%~N{Z^05h(XG;iU)_$H`^jBa^J*jDct0EFf;kQtc73UHy@BB`ZKyg2Y5H{ zCK-e`;!Sy(mnjDhNGv zY%7yh9h6U3BDHcAlie#-L`&-1nclvtQjN}3a=0PZkgSW;?P+RGvCrE&-}qkUj(I($c!CgqQ4X*LQh5MrGx;WU{w}ySfsI7yZ7{xL8}Lu*4Vn zPw88v(Tha&vKn@j)zVQF>k9bobu=-BtGW_)mKN}1@d>7-?G=foYh6t7$`REoOM2ou zi+85AJvB-^)|}FV8#9K{d+DXRmlD^lzdYJ-L@s$vcBkBilK7)ivqwvJZao@{x4qHR zYZ#f0!Cqe4``CuN?yy^NTbJB!mU0#CM0|mp%H}1rYo`{t1yzP zOU9SCZhdLNQm^$t5-4bRi12z zp(C|!nA8xvAsP7`r#!}+>F=MJ>960h!Emi}c_S6&L*@R>k$~#Y>Ak%=fRVv6;=OJS z>^OLE$Bu(FK6dpvF1tLHT&f7RwRx)Y|JxFcZV`a(#A0Eb@Ta!F#XNEA-*M?mV#pbwD2;yMSZts%7Iucq|Kl43 zK5_=ak*z8$@c;1NA*Y1#1GE{|2*^qxrRXV5SG9;LN3fVwK#>CxS&e9_uBCjd&Z@F} zrUQQW;;BEPy@h#Tbv+>KY8QKf z$%-n`Kwsahp>R0#YG2>LYJ7D6;Mw|UwEpbi{?XO=>+27n@9H{#c>U|2#IAjD^ynAY zVxNQ_?d}X^JlfwGi=Etgel%d3fzk6jd$V`nuKnz@+PCj!357XO_toI-?|VA`OXVVA z5&d=hYZWWs!U7`sP0-@c%PHt*|Hom|L_sY^T3t3cEe=a`1Kk3+0ayZ@0~ml%@hk9U zIs^QD7cn2cIY1M@1icU6K|mG20EFz(%g9fgs2Lvd3LT+OStpxj*QE+6BVCqmNDI>E z(tW;;2l*WTm#fB;lgCDmue~ZgOULf) z^lWHie0u!&$n5x7=+K!^?`U>+Hanf5Zu@dI3tLav*D`VC8nLfvW8fX4GpKv*Yuau| PipyF8785szr + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/listen1_chrome_extension/fonts/listen1-icon.ttf b/app/listen1_chrome_extension/fonts/listen1-icon.ttf new file mode 100644 index 0000000000000000000000000000000000000000..80e4eb8e414a308e9d80ed964dbebe9625e434d3 GIT binary patch literal 3460 zcma)9Z){W76+ib~$B+DVT-$jt+}4g0zc`7V#P-Vz5a1O?lyv-C=@OI(=8%{Wl-MZ* z0sT&yJs&qY&)}ZGsNv#%HtHU;kn!=tbywXD)wo9(JPD zPl|EkyvSaoDkABp(g)yNbl&U^rC7C)ThkcKey|xtML#c;3uJHr2E|^iw2+MmZ32QA zbKcyR3X+TZz^|coB;m&>RP>ii<+431R3sZ`<$owH%v-xIBL*qY8lFU?Z?Z*J<-Up6 zRldpbgJ$x1Sr@;;Z{8Bk&?dVLg&wBb_{a)t7=(d4*?Kja6Gku+%`!UQVm)_kyxv6h(TX)Y01UcuO zQT01&TVktJFzV`)(biO3A{_3lskMF(8{GAJs;gnI!QM;1URS@lt9w@!uiDqE@A7zz z`ueTOu7n-e z0)9B3U|QPtNVu+TXNp&js9ssp6W3Y1KdtR;QsS}BlpfreF^r*0&$m3ExNiOV;elgv z)yuLw*R4%~5v-HO|~WjGeP~DrFfv$1JlCz^9fuF^*m1bY$F4rbWtXR(OLf7X9#2E*zni1c z%>r=W*2WsO;xrx;YQD!u8oP@qdQ^Bt9}``fM+c8ocr+h->ZS~Z_#)4sdU(i33T>ok zanjh)K*SsNMzpXVNNEc8SmX z1-4j5@HqhFT{_3NN+sx{YNk{(xtgifOh@u`Ju$LhVi%`SHXlxn5U@aQfB3oWTG6rlr0Nd`a z*rvld>5^@cbqTiFRsw@jBc$-Fe44_vlLoQ2ij>)#M54vdFS|VsBdtcouNfKEr=W8; zJB+m6izFl%erHM&(^aN0mHje4)~;!JO>1utptX-C#=?zg;c%>dI2H@zhJWq&8_W~8 z{uP(5Bu1SDD$U%CV_|2x(%-*9-~(qNT-k>568|^CxS&e9_uBCiy?y9nKrvrZX^6Ar8zkGhQu&}iHwDtA132?6GVQG0) z@bqb8Rc>L)G91aaK11AO0f-4v`$DLF8N@^_ZUSNkVXwA^?daE1fm9$8h-eYbu=0384@R3G)&Vld8lMaxB_O$V5VT0hDcYT@-k}9BJPz=J7^E8&PvH~^5#mBajI;y z&8*a#lv8>uDU~a#-o-pPbv+>K>UQ=llND8>;oZAm3WdX=mv-+SUW-p0968q-jkcZ} zIXJNve`WpA3){C}IJ*9ok7Cz8KYsl4Yq5_)4^MZNG9I4qti?|4yf6_k&A`NkokRIM zZ#IAWY4e+R@`T15X!+mB$KUt#|A%Tt!6N$0wwLQx-{mD_@|&Q=mzUEp&;E|Xriq4L zthBama7G-Kmd_T^BJQ-UUDhzyy5&?-4))zyO5o)oaL4 z&rl~K;zc?}pRj(GW7nlRDI;B$Zb(bgXVN{sjtBVy|EH_b^+Vgz4YZfs_UsjpY@*UN z(AyP%7%KLPZxX)7E>!p&{9P5?1^h|{7tz>K!9}&7uHZHJj(HzZ%UspqtjCChOVmI= zuHYQ}?^bXZ@V6^?6*W;;1$Tpgs)E;0nwDp#PtIp^J@M&@e2!+I?YG(Wdy#OUsuycmS>BN&v z9LVS9LsQvY_Qd#nb~1G2Y-ngAzbBv1C1}7lbRMQo*?tN0$88@c!8<}{(GS^v?t!Fm NDuELd{~W%i{U0kItIYra literal 0 HcmV?d00001 diff --git a/app/listen1_chrome_extension/fonts/listen1-icon.woff b/app/listen1_chrome_extension/fonts/listen1-icon.woff new file mode 100644 index 0000000000000000000000000000000000000000..617652eb082c31f8013bed5a26396582431636da GIT binary patch literal 3536 zcma)9eQZKlUwFs^I(8eURKdg4`Uu`s4zqIv_Op~TsK*c6)(j@%6-+k|e zgaR$s@7#CJx#ymbd(XY+`PAONK4OGc`)8`Q-aoKuf#2Wu?(awvu{Gdk1bCist79{x zv*1mFeqMkwc;jaiqbCIKkD!IDfclB)(?`Mk6H%pKz}%&&z~uPo5u&QkFy1Y|_w%0L zO@c{OT@SiRfcy^s>*UPbi{Pa}L!OQdQ{~WfZcNBs1TFaKhQn*$pBa4-cB?-C9kL)q z`?8}m|LTn$v$+#xeOiwCktog ze<&_zhBbhW5rdS+(qi)@B7LJ}dd2=X@jA-aIexHAJ}>Lwm-zL&B#HTquF*l>$NNYI z;f;7xUgl-W!Glr<`@Q*=R5agW2TBU$imT;PkYrw|c<`V}QZ?ILQrKqmJ*fx_XJM-k zwz$yfgCGN({o)IDy;u}xU33?AIaY87FYrxNkJWhwl3G&Pz?23>j;aZ!Mk7q$z&0~k z)j|1mCDJI@G18mFeB9I@Rb+B}ZCfEy<=x)1J2W6#KlZ_m%HvK8$Ydo6~+1 z{V>zh-o6jRTyp81okuqI^l$C#8iF9_ygjOZTWv{fkqSmlZ8F-NYDt8{?N!z0_hbD# zUrTk=?J?MU>DOv%H+6LGtl$-UyY-zOk5OB@C7B$k;I3_n#M6FXWn9D-Di`?@{|SAI zG!SwQWrC$`REoOM2oei}$9r zJq=1c)}GRX>obNiaN*geXA@V=zdSfFDObECyHjpMN&G=+*rTO;Hy?||yI$!ZFpSLl z-~g{2c<8`Qci64C%?oZfOSznVBEHD;#J_CC5hVS8P-``>dty zym0cwS;DVcl?tKYlkr-#_>;jLwjKf{5r*MSPJ-yLa;YU%D&vO)2t0!Uoz(d!uaDo=J}qa%%O zY^fnuLo!MQP9^A@-M4Rcc3<=Mb%tw=%Nwbw9LVST|P=P$;BZbz}Q`l*&XdvPZdm~y{52Q2&Yb@>yac@|6M}`@U zW=jjRSeL@9W{54Bvxbqk9-he?rMv_JWU0Uw%1AyNfV@j*_!g-oDqba1Dw$l#)Jmq~ z@~w}XcdX956KD0JyL~@d4-!5z=A-@6FL_+l3`>E+W|$E-FR+<7E0~2i$eB276)4ZK zx!4VHzZN6|o1JHd(1Gmvgnuku6gq?(I^$Pb%{H^Gm0gi8cA8l>-)YW6E|0pBN6x`t zhFe&q8Wu)lOGpND!7vxt(lU}U;M;!qc6-@39l=Q#ERW0!@XhiP7@Qg+gVZo|43Ll_^YRzle{tYFbXy zT3Z8Xt;30ta6MW$9BUnn#lkq@UpxLf^Tf@6#idJ$VOxPCjd|f%Y_K&Jw$+vX{tW^j z*otsu>&lD#-~6|zDPfA!M(jpFRstzSPieZUMN~P0U{V1^4n$-%qN%!;@~t|n%JP{G z_}xpVPF=qD{AhlDaph_0>1h#QAJ0S5(u&}zQ^tzi{Gw^tk}W-kILQK#6QcHoQ2R2- ziE5k#e zi0dj;UP8@Tz`4?CJMBi*SuQ#Dy}4Xu>?+%6F`ZhIvP-XXrE*2pJD3N%t_NgY-Nv3` zvZ6{fxNFx7p>R0#!meF|tMRb|LuZhU8{fQ{BQ$11)BlD({+_4zKU6IW z7SU&0U#eMomltu9Uk5F|yzGW~)^{8hO*HgE)9SX)9d77k8STD=6t5S`WkuFNtq($j- z=?-7RgM6O<(^c>Kq2=j1+Cy$@_HslP;dFKMwi6FS#a@n0!q?b2htI*^>EJHlmmFMV zW0Ql6YCq-RRrrp1A6d&>mEf$!h>c5BM?ZFO4*qu>+y(q?2d|(8>Tqy3_$M8_3g7fg z(^Dtr#o z>UkIs!B2^~Hi8W_v%&gHTR o>a!f3gR2u(T*CcPE5;+>9j4Rh2dp@ELsA5lz>bN34qwy$4-_h}@Bjb+ literal 0 HcmV?d00001 diff --git a/app/listen1_chrome_extension/i18n/en_US.json b/app/listen1_chrome_extension/i18n/en_US.json new file mode 100644 index 0000000..e5297f3 --- /dev/null +++ b/app/listen1_chrome_extension/i18n/en_US.json @@ -0,0 +1,85 @@ +{ + "HELLO" : "hi", + "_NETEASE_MUSIC": "Netease", + "_QQ_MUSIC": "QQ", + "_XIAMI_MUSIC": "Xiami", + "_KUGOU_MUSIC": "Kugou", + "_KUWO_MUSIC": "Kuwo", + "_BILIBILI_MUSIC": "Bilibili", + "_PLATFORM_UNION": "Platforms", + "_PLAYLISTS": "PLAYLISTS", + "_MY_MUSIC": "My Music", + "_PLAY_ALL": "Play All", + "_ADD_TO_PLAYLIST": "Add to Playlist", + "_EDIT": "Edit", + "_IMPORT": "Import", + "_IMPORT_PLAYLIST": "Import Playlist", + "_ORIGIN_LINK": "Origin link", + "_SONGS": "Songs", + "_ARTISTS": "Artists", + "_ALBUMS": "Albums", + "_OPERATION": "Tools", + "_CREATE_PLAYLIST": "Create Playlist", + "_CANCEL": "Cancel", + "_CREATE_AND_ADD_PLAYLIST": "Create and Add", + "_REMOVE_FROM_PLAYLIST": "Remove", + "_ADD_TO_QUEUE": "Add to Queue", + "_ARTIST": "Artist", + "_ALBUM": "Album", + "_PLAYLIST_TITLE": "Playlist Title", + "_PLAYLIST_COVER_IMAGE_URL": "Cover Image URL", + "_INPUT_PLAYLIST_TITLE": "Input Playlist Title", + "_INPUT_PLAYLIST_COVER_IMAGE_URL": "Input Cover Image URL", + "_EDIT_PLAYLIST": "Edit Playlist", + "_REMOVE_PLAYLIST": "Remove Playlist", + "_OPENING_LASTFM_PAGE":"Opening Last.fm页面...", + "_CONFIRM_NOTICE_LASTFM": "Please click \"Yes, all access\" in new page, allow Listen 1 access your account.", + "_AUTHORIZED_FINISHED": "Authorized Finished", + "_AUTHORIZED_REOPEN": "I Have Problem, try again", + "_PLAYLIST_LINK": "Playlist Link", + "_OPEN_PLAYLIST": "Open Playlist", + "_OPENING_GITHUB_PAGE": "Opening Github.com页面...", + "_CONFIRM_NOTICE_GITHUB": "Please click \"Authencate\" in new page, allow Listen 1 access your account", + "_CREATE_PLAYLIST_BACKUP": "Create Playlist Backup", + "_CREATE_PUBLIC_BACKUP": "Create Public Backup", + "_CREATE_PRIVATE_BACKUP": "Create Private Backup", + "_BACKUP_PLAYLIST": "Backup Playlists", + "_BACKUP_WARNING": "Reinstall or clear cache will lost all your playlists, backup is STORNG RECOMMENDED.", + "_EXPORT_TO_LOCAL_FILE": "Export to Local File", + "_EXPORT_TO_GITHUB_GIST": "Export to Github Gist", + "_RECOVER_PLAYLIST": "Recover Playlists", + "_RECOVER_WARNING": "Choose Backup File. Notice: It will overwrite current playlists.", + "_RECOVER_FROM_LOCAL_FILE": "Recover from Local File", + "_RECOVER_FROM_GITHUB_GIST": "Recover from Github Gist", + "_CONNECT_TO_GITHUB": "Connect to Github.com", + "_STATUS": "Status", + "_RECONNECT": "Reconnect", + "_CANCEL_CONNECT": "Cancel Connect", + "_SHORTCUTS": "Shortcuts", + "_VIEW_SHORTCUTS_LIST": "View Shortcuts List", + "_GLOBAL_SHORTCUTS_NOTICE": "Enable Global Shortcuts: Ctrl(Cmd) + Alt + Left Arrow (Previous Track),Ctrl(Cmd) + Alt + Right Arrow (Next Track)", + "_CONNECT_TO_LASTFM": "Connect to Last.fm", + "_ABOUT": "About", + "_HOMEPAGE": "Homepage", + "_EMAIL": "Email", + "_DESIGNER": "Designer", + "_VERSION": "Version", + "_LICENSE_NOTICE": "(This software is free and open source under MIT license)", + "_TOTAL_SONG_PREFIX": "Total ", + "_TOTAL_SONG_POSTFIX": " Songs", + "_CLEAR_ALL": "Clear All", + "_SEARCH_PLACEHOLDER": "Search for song, artist or album", + "_LANGUAGE": "Language", + "_ADD_TO_PLAYLIST_SUCCESS": "Success: Add to Playlist", + "_EDIT_PLAYLIST_SUCCESS": "Success: Edit Playlist", + "_IMPORTING_PLAYLIST": "Importing playlists...", + "_IMPORTING_PLAYLIST_SUCCESS": "Success: Import Playlists", + "_REMOVE_PLAYLIST_SUCCESS": "Success: Remove Playlist", + "_ADD_TO_QUEUE_SUCCESS": "Success: Add to Queue", + "_COPYRIGHT_ISSUE": "Fail because copyright issue, Search other platform instead", + "_ADD_TO_PLAYLIST_SUCCESS": "Success: Add to playlist", + "_INPUT_NEW_PLAYLIST_TITLE": "Input New Playlist Title", + "_FAIL_OPEN_PLAYLIST_URL": "Fail to Open Playlist url", + "_EXAMPLE": "Example:", + "_COMFIRM": "Confirm" +} \ No newline at end of file diff --git a/app/listen1_chrome_extension/i18n/zh_CN.json b/app/listen1_chrome_extension/i18n/zh_CN.json new file mode 100644 index 0000000..5bc3416 --- /dev/null +++ b/app/listen1_chrome_extension/i18n/zh_CN.json @@ -0,0 +1,85 @@ +{ + "HELLO" : "你好", + "_NETEASE_MUSIC": "网易云音乐", + "_QQ_MUSIC": "QQ音乐", + "_XIAMI_MUSIC": "QQ音乐", + "_KUGOU_MUSIC": "酷狗音乐", + "_KUWO_MUSIC": "酷我音乐", + "_BILIBILI_MUSIC": "哔哩哔哩", + "_PLATFORM_UNION": "平台聚合", + "_PLAYLISTS": "精选歌单", + "_MY_MUSIC": "我的音乐", + "_PLAY_ALL": "播放全部", + "_ADD_TO_PLAYLIST": "添加到歌单", + "_EDIT": "编辑", + "_IMPORT": "导入", + "_IMPORT_PLAYLIST": "导入歌单", + "_ORIGIN_LINK": "链接", + "_SONGS": "歌曲名", + "_ARTISTS": "歌手", + "_ALBUMS": "专辑名", + "_OPERATION": "操作", + "_CREATE_PLAYLIST": "新建歌单", + "_CANCEL": "取消", + "_CREATE_AND_ADD_PLAYLIST": "创建并添加", + "_REMOVE_FROM_PLAYLIST": "从歌单删除", + "_ADD_TO_QUEUE": "添加到当前播放", + "_ARTIST": "歌手", + "_ALBUM": "专辑名", + "_PLAYLIST_TITLE": "歌单名称", + "_PLAYLIST_COVER_IMAGE_URL": "封面图片url", + "_INPUT_PLAYLIST_TITLE": "输入歌单名称", + "_INPUT_PLAYLIST_COVER_IMAGE_URL": "输入封面URL", + "_EDIT_PLAYLIST": "编辑歌单", + "_REMOVE_PLAYLIST": "删除歌单", + "_OPENING_LASTFM_PAGE":"正在打开Last.fm页面...", + "_CONFIRM_NOTICE_LASTFM": "请在打开的页面点击\"Yes, all access\", 允许Listen 1访问你的账户。", + "_AUTHORIZED_FINISHED": "已经完成授权", + "_AUTHORIZED_REOPEN": "遇到问题,再次打开授权页", + "_PLAYLIST_LINK": "歌单链接", + "_OPEN_PLAYLIST": "打开歌单", + "_OPENING_GITHUB_PAGE": "正在打开Github.com页面...", + "_CONFIRM_NOTICE_GITHUB": "请在打开的页面点击\"Authencate\", 允许Listen 1访问你的账户。", + "_CREATE_PLAYLIST_BACKUP": "创建歌单备份", + "_CREATE_PUBLIC_BACKUP": "创建公开备份", + "_CREATE_PRIVATE_BACKUP": "创建私有备份", + "_BACKUP_PLAYLIST": "备份歌单", + "_BACKUP_WARNING": "重装插件或清除缓存数据会导致我的歌单数据丢失,强烈建议在这些操作前,备份我的歌单。", + "_EXPORT_TO_LOCAL_FILE": "导出到本地文件", + "_EXPORT_TO_GITHUB_GIST": "导出到Github Gist", + "_RECOVER_PLAYLIST": "从备份恢复", + "_RECOVER_WARNING": "选择备份文件,恢复我的歌单。注意:恢复我的歌单会覆盖现有的歌单。", + "_RECOVER_FROM_LOCAL_FILE": "从本地文件导入", + "_RECOVER_FROM_GITHUB_GIST": "从Github Gist导入", + "_CONNECT_TO_GITHUB": "连接到Github.com", + "_STATUS": "状态", + "_RECONNECT": "重新连接", + "_CANCEL_CONNECT": "取消连接", + "_SHORTCUTS": "快捷键", + "_VIEW_SHORTCUTS_LIST": "查看快捷键列表", + "_GLOBAL_SHORTCUTS_NOTICE": "启用全局快捷键: Ctrl(Cmd) + Alt + 左箭头 (上一首),Ctrl(Cmd) + Alt + 右箭头 (下一首)", + "_CONNECT_TO_LASTFM": "连接到last.fm", + "_ABOUT": "关于", + "_HOMEPAGE": "主页", + "_EMAIL": "邮箱", + "_DESIGNER": "主题设计", + "_VERSION": "当前版本", + "_LICENSE_NOTICE": "(本软件基于MIT协议开源免费)", + "_TOTAL_SONG_PREFIX": "共", + "_TOTAL_SONG_POSTFIX": "首", + "_CLEAR_ALL": "清空", + "_SEARCH_PLACEHOLDER": "输入歌曲名,歌手或专辑", + "_LANGUAGE": "语言", + "_ADD_TO_PLAYLIST_SUCCESS": "添加到歌单成功", + "_EDIT_PLAYLIST_SUCCESS": "编辑歌单成功", + "_IMPORTING_PLAYLIST": "正在导入歌单...", + "_IMPORTING_PLAYLIST_SUCCESS": "导入歌单成功", + "_REMOVE_PLAYLIST_SUCCESS": "删除歌单成功", + "_ADD_TO_QUEUE_SUCCESS": "添加到当前播放成功", + "_COPYRIGHT_ISSUE": "版权原因无法播放,请搜索其他平台", + "_ADD_TO_PLAYLIST_SUCCESS": "收藏到我的歌单成功", + "_INPUT_NEW_PLAYLIST_TITLE": "输入新歌单名称", + "_FAIL_OPEN_PLAYLIST_URL": "未能打开输入的歌单地址", + "_EXAMPLE": "例如", + "_COMFIRM": "确认" +} \ No newline at end of file diff --git a/app/listen1_chrome_extension/images/feather-sprite.svg b/app/listen1_chrome_extension/images/feather-sprite.svg new file mode 100644 index 0000000..0a6c4ba --- /dev/null +++ b/app/listen1_chrome_extension/images/feather-sprite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/listen1_chrome_extension/images/loading.svg b/app/listen1_chrome_extension/images/loading.svg new file mode 100644 index 0000000..6996bcb --- /dev/null +++ b/app/listen1_chrome_extension/images/loading.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/listen1_chrome_extension/js/app.js b/app/listen1_chrome_extension/js/app.js index 0bfb50c..e292027 100644 --- a/app/listen1_chrome_extension/js/app.js +++ b/app/listen1_chrome_extension/js/app.js @@ -10,7 +10,7 @@ return value && JSON.parse(value); } - var app = angular.module('listenone', ['angularSoundManager', 'ui-notification', 'loWebManager', 'cfp.hotkeys', 'lastfmClient', 'githubClient']) + var app = angular.module('listenone', ['angularSoundManager', 'ui-notification', 'loWebManager', 'cfp.hotkeys', 'lastfmClient', 'githubClient', 'pascalprecht.translate']) app.config( [ '$compileProvider', @@ -44,13 +44,26 @@ }); }); + app.config(['$translateProvider', function($translateProvider) { - app.run(['angularPlayer', 'Notification', 'loWeb', function(angularPlayer, Notification, loWeb) { + // Register a loader for the static files + $translateProvider.useStaticFilesLoader({ + prefix: './i18n/', + suffix: '.json' + }); + $translateProvider.use('zh_CN'); + // Tell the module what language to use by default + $translateProvider.preferredLanguage('zh_CN'); + }]); + + app.run(['angularPlayer', 'Notification', 'loWeb', '$translate', + function(angularPlayer, Notification, loWeb, $translate) { angularPlayer.setBootstrapTrack( loWeb.bootstrapTrack( function(){}, function(){ - Notification.info('版权原因无法播放,请搜索其他平台'); + var d = {message: $translate.instant('_COPYRIGHT_ISSUE'), replaceMessage: true} + Notification.info(d); }) ); }]); @@ -92,17 +105,42 @@ } } + + app.controller('TranslateController', ['$scope', '$translate', '$http', function($scope, $translate, $http) { + //var defaultLang = 'zh_CN'; + var defaultLang = localStorage.getObject('language') || 'zh_CN'; + + + $scope.setLang = function(langKey) { + // You can change the language during runtime + $translate.use(langKey).then(function () { + + $http.get('./i18n/zh_CN.json') + .then(function(res){ + for(var k in res.data) { + $scope[k] = $translate.instant(k); + } + }); + localStorage.setObject('language', langKey); + }); + }; + + $scope.setLang(defaultLang); + + }]); + // control main view of page, it can be called any place app.controller('NavigationController', ['$scope', '$http', '$httpParamSerializerJQLike', '$timeout', 'angularPlayer', 'Notification', '$rootScope', 'loWeb', - 'hotkeys', 'lastfm', 'github', 'gist', + 'hotkeys', 'lastfm', 'github', 'gist', '$translate', function($scope, $http, $httpParamSerializerJQLike, $timeout, angularPlayer, Notification, $rootScope, - loWeb, hotkeys, lastfm, github, gist) { + loWeb, hotkeys, lastfm, github, gist, $translate) { $rootScope.page_title = "Listen 1"; $scope.window_url_stack = []; + $scope.window_poped_url_stack = []; $scope.current_tag = 2; $scope.is_window_hidden = 1; $scope.is_dialog_hidden = 1; @@ -123,26 +161,27 @@ $scope.isDoubanLogin = data; }); - $scope.minmin = function() { - const remote = nodeRequire('electron').remote - remote.getCurrentWindow().minimize(); - console.log('111'); - } // tag $scope.showTag = function(tag_id){ $scope.current_tag = tag_id; $scope.is_window_hidden = 1; $scope.window_url_stack = []; + $scope.window_poped_url_stack = []; $scope.closeWindow(); }; + $scope.$on('search:keyword_change', function(event, data) { + $scope.showTag(3); + }); + // playlist window $scope.resetWindow = function() { - $scope.cover_img_url = 'images/loading.gif'; + $scope.cover_img_url = 'images/loading.svg'; $scope.playlist_title = ''; $scope.playlist_source_url = ''; $scope.songs = []; $scope.window_type = 'list'; + document.getElementsByClassName('browser')[0].scrollTop = 0; }; $scope.showWindow = function(url){ @@ -160,9 +199,11 @@ if (url == '/now_playing') { $scope.window_type = 'track'; $scope.window_url_stack.push(url); + $scope.window_poped_url_stack = []; return; } $scope.window_url_stack.push(url); + $scope.window_poped_url_stack = []; loWeb.get(url).success(function(data) { if (data.status == '0') { @@ -184,17 +225,10 @@ $scope.is_window_hidden = 1; $scope.resetWindow(); $scope.window_url_stack = []; + $scope.window_poped_url_stack = []; }; - $scope.popWindow = function() { - $scope.window_url_stack.pop(); - if($scope.window_url_stack.length === 0) { - $scope.closeWindow(); - } - else { - $scope.resetWindow(); - var url = $scope.window_url_stack[$scope.window_url_stack.length-1]; - + function refreshWindow(url){ if (url == '/now_playing') { $scope.window_type = 'track'; return; @@ -207,6 +241,36 @@ $scope.playlist_source_url = data.info.source_url; $scope.is_mine = (data.info.id.slice(0,2) == 'my'); }); + } + $scope.popWindow = function() { + var poped = $scope.window_url_stack.pop(); + $scope.window_poped_url_stack.push(poped); + if($scope.window_url_stack.length === 0) { + $scope.closeWindow(); + } + else { + $scope.resetWindow(); + var url = $scope.window_url_stack[$scope.window_url_stack.length-1]; + refreshWindow(url); + } + }; + + $scope.toggleWindow = function(url){ + if ($scope.window_url_stack.length > 0 && $scope.window_url_stack[$scope.window_url_stack.length-1] == url) { + return $scope.popWindow(); + } + return $scope.showWindow(url); + } + + $scope.forwardWindow = function() { + if($scope.window_poped_url_stack.length === 0) { + return; + } + else { + $scope.resetWindow(); + var url = $scope.window_poped_url_stack.pop(); + $scope.window_url_stack.push(url); + refreshWindow(url); } }; @@ -243,12 +307,12 @@ $scope.showDialog = function(dialog_type, data) { $scope.is_dialog_hidden = 0; - var dialogWidth = 480; + var dialogWidth = 285; var left = $(window).width()/2 - dialogWidth/2; $scope.myStyle = {'left': left + 'px'}; if (dialog_type == 0) { - $scope.dialog_title = '添加到歌单'; + $scope.dialog_title = $translate.instant('_ADD_TO_PLAYLIST'); var url = '/show_myplaylist'; $scope.dialog_song = data; loWeb.get(url).success(function(data) { @@ -256,27 +320,27 @@ }); } - if (dialog_type == 2) { - $scope.dialog_title = '登录豆瓣'; - $scope.dialog_type = 2; - } + // if (dialog_type == 2) { + // $scope.dialog_title = '登录豆瓣'; + // $scope.dialog_type = 2; + // } if (dialog_type == 3) { - $scope.dialog_title = '修改歌单'; + $scope.dialog_title = $translate.instant('_EDIT_PLAYLIST'); $scope.dialog_type = 3; $scope.dialog_cover_img_url = data.cover_img_url; $scope.dialog_playlist_title = data.playlist_title; } if (dialog_type == 4) { - $scope.dialog_title = '连接到Last.fm'; + $scope.dialog_title = $translate.instant('_CONNECT_TO_LASTFM'); $scope.dialog_type = 4; } if (dialog_type == 5) { - $scope.dialog_title = '打开歌单'; + $scope.dialog_title = $translate.instant('_OPEN_PLAYLIST'); $scope.dialog_type = 5; } if (dialog_type == 6) { - $scope.dialog_title = '歌单导入合并'; + $scope.dialog_title = $translate.instant('_IMPORT_PLAYLIST'); var url = '/show_myplaylist'; loWeb.get(url).success(function(data) { $scope.myplaylist = data.result; @@ -284,11 +348,11 @@ $scope.dialog_type = 6; } if (dialog_type == 7) { - $scope.dialog_title = '连接到Github.com'; + $scope.dialog_title = $translate.instant('_CONNECT_TO_GITHUB'); $scope.dialog_type = 7; } if (dialog_type == 8) { - $scope.dialog_title = '导出到Github Gist'; + $scope.dialog_title = $translate.instant('_EXPORT_TO_GITHUB_GIST'); $scope.dialog_type = 8; gist.listExistBackup().then(function(res){ $scope.myBackup = res; @@ -297,7 +361,7 @@ }); } if (dialog_type == 10) { - $scope.dialog_title = '从Github Gist导入'; + $scope.dialog_title = $translate.instant('_RECOVER_FROM_GITHUB_GIST'); $scope.dialog_type = 10; gist.listExistBackup().then(function(res){ $scope.myBackup = res; @@ -320,7 +384,7 @@ 'Content-Type': 'application/x-www-form-urlencoded' } }).success(function() { - Notification.success('添加到歌单成功'); + Notification.success($translate.instant('_ADD_TO_PLAYLIST_SUCCESS')); $scope.closeDialog(); // add to current playing list if (option_id == $scope.current_list_id) { @@ -352,7 +416,7 @@ } }).success(function() { $rootScope.$broadcast('myplaylist:update'); - Notification.success('添加到歌单成功'); + Notification.success($translate.instant('_ADD_TO_PLAYLIST_SUCCESS')); $scope.closeDialog(); }); }; @@ -375,13 +439,13 @@ $rootScope.$broadcast('myplaylist:update'); $scope.playlist_title = $scope.dialog_playlist_title; $scope.cover_img_url = $scope.dialog_cover_img_url; - Notification.success('修改歌单成功'); + Notification.success($translate.instant('_EDIT_PLAYLIST_SUCCESS')); $scope.closeDialog(); }); }; $scope.mergePlaylist = function(target_list_id) { - Notification.info('正在合并导入歌单……'); + Notification.info($translate.instant('_IMPORTING_PLAYLIST')); var url = '/merge_playlist'; loWeb.post({ url: url, @@ -394,7 +458,7 @@ 'Content-Type': 'application/x-www-form-urlencoded' } }).success(function() { - Notification.success('合并歌单成功'); + Notification.success($translate.instant('_IMPORTING_PLAYLIST_SUCCESS')); $scope.closeDialog(); $scope.popWindow(); $scope.showPlaylist($scope.list_id); @@ -420,7 +484,7 @@ if (index > -1) { $scope.songs.splice(index, 1); } - Notification.success('删除成功'); + Notification.success($translate.instant('_REMOVE_PLAYLIST_SUCCESS')); }); } @@ -459,12 +523,13 @@ $timeout(function(){ //add songs to playlist angularPlayer.addTrackArray($scope.songs); - Notification.success("添加到当前播放成功"); + Notification.success($translate.instant('_ADD_TO_QUEUE_SUCCESS')); }, 0); }; $scope.copyrightNotice = function() { - Notification.info("版权原因无法播放,请搜索其他平台"); + var d = {message: $translate.instant('_COPYRIGHT_ISSUE'), replaceMessage: true} + Notification.info(d); }; $scope.clonePlaylist = function(list_id){ @@ -481,7 +546,7 @@ }).success(function() { $rootScope.$broadcast('myplaylist:update'); $scope.closeWindow(); - Notification.success('收藏到我的歌单成功'); + Notification.success($translate.instant('_ADD_TO_PLAYLIST_SUCCESS')); }); }; @@ -501,7 +566,7 @@ $rootScope.$broadcast('myplaylist:update'); $scope.closeDialog(); $scope.closeWindow(); - Notification.success('删除歌单成功'); + Notification.success($translate.instant('_REMOVE_PLAYLIST_SUCCESS')); }); }; @@ -554,6 +619,7 @@ var value = data[key]; localStorage.setObject(key, value); } + $rootScope.$broadcast('myplaylist:update'); Notification.success("成功导入我的歌单"); } }; @@ -588,14 +654,16 @@ $scope.importMySettingsFromGist = function(gistId){ $scope.gistRestoreLoading = true; gist.importMySettingsFromGist(gistId).then(function(raw){ - var data = gist.gist2json(raw); - for ( var key in data) { - var value = data[key]; - localStorage.setObject(key, value); - } - Notification.clearAll(); - Notification.success("导入我的歌单成功"); - $scope.gistRestoreLoading = false; + gist.gist2json(raw, function(data){ + for ( var key in data) { + var value = data[key]; + localStorage.setObject(key, value); + } + Notification.clearAll(); + Notification.success("导入我的歌单成功"); + $scope.gistRestoreLoading = false; + $rootScope.$broadcast('myplaylist:update'); + }); },function(err){ Notification.clearAll(); if(err==404){ @@ -638,7 +706,7 @@ $scope.showPlaylist(result.id); } else { - Notification.info('未能打开输入的歌单地址'); + Notification.info($translate.instant('_FAIL_OPEN_PLAYLIST_URL')); } }); } @@ -682,6 +750,14 @@ $scope.scrobbleTrackId = null; $scope.scrobbleTimer = new Timer(); $scope.adjustVolume = angularPlayer.adjustVolume; + $scope.enableGloablShortcut = false; + $scope.isChrome = (typeof chrome !== 'undefined'); + $scope.isMac = false; + + if (!$scope.isChrome) { + $scope.isMac = require('electron').remote.process.platform == 'darwin'; + } + function switchMode(mode){ //playmode 0:loop 1:shuffle 2:repeat one @@ -729,6 +805,8 @@ else { $timeout(function(){angularPlayer.adjustVolumeSlider($scope.volume)},0); } + $scope.enableGlobalShortCut = localStorage.getObject('enable_global_shortcut'); + $scope.applyGlobalShortcut(); } $scope.saveLocalSettings = function() { @@ -1005,10 +1083,10 @@ lastObject = lyricObject; } if (lastObject && lastObject.lineNumber != $scope.lyricLineNumber) { - var lineHeight = 20; + var lineHeight = 21; var lineElement = $(".lyric p")[lastObject.lineNumber]; - var windowHeight = 270; - var AdditionOffset = 4; + var windowHeight = 380; + var AdditionOffset = -158; var offset = lineElement.offsetTop - windowHeight/2 + AdditionOffset; $(".lyric").animate({ scrollTop: offset+"px" }, 500); $scope.lyricLineNumber = lastObject.lineNumber; @@ -1099,10 +1177,44 @@ $timeout(function(){angularPlayer.adjustVolume(false);}); } }); + + // electron global shortcuts + $scope.applyGlobalShortcut = function(toggle) { + if (typeof chrome !== 'undefined') { + return; + } + var message = ''; + if(toggle === true) { + $scope.enableGlobalShortCut = !$scope.enableGlobalShortCut; + } + if ($scope.enableGlobalShortCut == true) { + message = 'enable_global_shortcut'; + } + else { + message = 'disable_global_shortcut'; + } + + // check if globalShortcuts is allowed + localStorage.setObject('enable_global_shortcut', $scope.enableGlobalShortCut); + + const {ipcRenderer} = require('electron'); + ipcRenderer.send('control', message); + } + + if (typeof chrome == 'undefined') { + require('electron').ipcRenderer.on('globalShortcut', (event, message) => { + if (message == 'right'){ + angularPlayer.nextTrack(); + } + else if (message == 'left') { + angularPlayer.prevTrack(); + } + }); + } }]); - app.controller('InstantSearchController', ['$scope', '$http', '$timeout', 'angularPlayer', 'loWeb', - function($scope, $http, $timeout, angularPlayer, loWeb) { + app.controller('InstantSearchController', ['$scope', '$http', '$timeout', '$rootScope', 'angularPlayer', 'loWeb', + function($scope, $http, $timeout, $rootScope, angularPlayer, loWeb) { $scope.originpagelog = [1, 1, 1, 1, 1, 1, 1]; // [网易,虾米,QQ,NULL,酷狗,酷我,bilibili] $scope.tab = 0; $scope.keywords = ''; @@ -1112,7 +1224,7 @@ $scope.curpage = 1; $scope.totalpage = 1; - $scope.changeTab = function(newTab){ + $scope.changeSourceTab = function(newTab){ $scope.loading = true; $scope.tab = newTab; $scope.result = []; @@ -1146,6 +1258,7 @@ }); function performSearch(){ + $rootScope.$broadcast('search:keyword_change', $scope.keywords); loWeb.get('/search?source=' + getSourceName($scope.tab) + '&keywords=' + $scope.keywords+'&curpage='+ $scope.curpage).success(function(data) { // update the textarea $scope.result = data.result; @@ -1248,8 +1361,8 @@ }; }]); - app.directive('addWithoutPlay', ['angularPlayer', 'Notification', - function (angularPlayer, Notification) { + app.directive('addWithoutPlay', ['angularPlayer', 'Notification', '$translate', + function (angularPlayer, Notification, $translate) { return { restrict: "EA", scope: { @@ -1258,7 +1371,7 @@ link: function (scope, element, attrs) { element.bind('click', function (event) { angularPlayer.addTrack(scope.song); - Notification.success("已添加到当前播放歌单"); + Notification.success($translate.instant('_ADD_TO_QUEUE_SUCCESS')); }); } }; @@ -1273,14 +1386,42 @@ }, link: function (scope, element, attrs) { element.bind('click', function (event) { + if( (typeof chrome) == 'undefined') { + // normal window for link + const {BrowserWindow} = require('electron').remote + let win = new BrowserWindow({width: 1000, height: 670}) + win.on('closed', () => { + win = null + }) + win.loadURL(scope.url); + return; + } $window.open(scope.url, '_blank'); }); } }; }]); - app.directive('infiniteScroll', ['$window', - function ($window) { + app.directive('windowControl', ['angularPlayer', '$window', + function (angularPlayer, $window) { + return { + restrict: "EA", + scope: { + action: "@windowControl" + }, + link: function (scope, element, attrs) { + element.bind('click', function (event) { + if( (typeof chrome) == 'undefined') { + const {ipcRenderer} = require('electron'); + ipcRenderer.send('control', scope.action); + } + }); + } + }; + }]); + + app.directive('infiniteScroll', ['$window', '$rootScope', + function ($window, $rootScope) { return { restrict: "EA", scope: { @@ -1304,9 +1445,14 @@ var height = contentElement.offsetHeight; var remain = height - bottom; + if (remain < 0) { + // page not shown + return; + } var offsetToload = 10; if (remain <= offsetToload) { - scope.$apply(scope.infiniteScroll); + //scope.$apply(scope.infiniteScroll); + $rootScope.$broadcast('infinite_scroll:hit_bottom', ''); } }); } @@ -1443,7 +1589,8 @@ }); }; - $scope.scrolling = function(){ + + $scope.$on('infinite_scroll:hit_bottom', function(event, data) { if ($scope.loading == true) { return } @@ -1453,7 +1600,7 @@ $scope.result = $scope.result.concat(data.result); $scope.loading = false; }); - } + }); $scope.isActiveTab = function(tab){ return $scope.tab === tab; @@ -1468,111 +1615,4 @@ }; }]); - // app.controller('ImportController', ['$http', - // '$httpParamSerializerJQLike', '$scope', '$interval', - // '$timeout', '$rootScope', 'Notification', 'angularPlayer', - // function($http, $httpParamSerializerJQLike, $scope, - // $interval, $timeout, $rootScope, Notification, angularPlayer){ - // $scope.validcode_url = ""; - // $scope.token = ""; - - // $scope.getLoginInfo = function(){ - // $http.get('/dbvalidcode').success(function(data) { - // if (data.isLogin == 0) { - // $scope.validcode_url = data.captcha.path; - // $scope.token = data.captcha.token; - // } - // else { - // // already login - // $scope.isDoubanLogin = true; - // $rootScope.$broadcast('isdoubanlogin:update', true); - // } - // }); - // }; - - // $scope.loginDouban = function(){ - // $scope.session.token = $scope.token; - // $http({ - // url: '/dblogin', - // method: 'POST', - // data: $httpParamSerializerJQLike($scope.session), - // headers: { - // 'Content-Type': 'application/x-www-form-urlencoded' - // } - // }).success(function(data) { - // if (data.result.success == '1') { - // $scope.isDoubanLogin = true; - // $rootScope.$broadcast('isdoubanlogin:update', true); - // Notification.success("登录豆瓣成功"); - // } - // else { - // $scope.validcode_url = data.result.path; - // $scope.token = data.result.token; - // } - // }); - // $scope.session.solution = ""; - // }; - - // $scope.logoutDouban = function() { - // $http({ - // url: '/dblogout', - // method: 'GET' - // }).success(function(data) { - // $scope.isDoubanLogin = false; - // $rootScope.$broadcast('isdoubanlogin:update', false); - // Notification.success("退出登录豆瓣成功"); - // $scope.getLoginInfo(); - // }); - // }; - - // $scope.importDoubanFav = function(){ - // $http({ - // url: '/dbfav', - // method: 'POST', - // data: $httpParamSerializerJQLike({command:'start'}), - // headers: { - // 'Content-Type': 'application/x-www-form-urlencoded' - // } - // }).success(function(data) { - // $scope.status = '正在进行中:' + data.result.progress + '%'; - // $scope.start(); - // }); - // }; - - // var promise; - - // $scope.start = function() { - // // stops any running interval to avoid two intervals running at the same time - // $scope.stop(); - - // // store the interval promise - // promise = $interval(poll, 1000); - // }; - - // $scope.stop = function() { - // $interval.cancel(promise); - // }; - // $scope.$on('$destroy', function() { - // $scope.stop(); - // }); - - // function poll(){ - // $http({ - // url: '/dbfav', - // method: 'POST', - // data: $httpParamSerializerJQLike({command:'status'}), - // headers: { - // 'Content-Type': 'application/x-www-form-urlencoded' - // } - // }).success(function(data) { - // $scope.status = '正在进行中:' + data.result.progress + '%'; - // if (data.result.progress == 100) { - // $scope.stop(); - // $scope.status = ''; - // Notification.success("红心兆赫已导入我的歌单"); - // } - // }); - // } - // }]); - })(); diff --git a/app/listen1_chrome_extension/js/background.js b/app/listen1_chrome_extension/js/background.js index 3515443..e7154d0 100644 --- a/app/listen1_chrome_extension/js/background.js +++ b/app/listen1_chrome_extension/js/background.js @@ -11,28 +11,36 @@ function hack_referer_header(details) { let replace_origin = true; let add_referer = true; let add_origin = true; - + var referer_value = ''; + if (details.url.indexOf("://music.163.com/") != -1) { referer_value = "http://music.163.com/"; } - + if (details.url.indexOf("://gist.githubusercontent.com/") != -1) { + referer_value = "https://gist.githubusercontent.com/"; + } + if (details.url.indexOf("api.xiami.com/") != -1 || details.url.indexOf('.xiami.com/song/playlist/id/') != -1) { referer_value = "https://www.xiami.com/"; } - if ((details.url.indexOf("y.qq.com/") != -1) || + if ((details.url.indexOf("c.y.qq.com/") != -1) || + (details.url.indexOf("i.y.qq.com/") != -1) || (details.url.indexOf("qqmusic.qq.com/") != -1) || (details.url.indexOf("music.qq.com/") != -1) || (details.url.indexOf("imgcache.qq.com/") != -1)) { - referer_value = "http://y.qq.com/"; + referer_value = "https://y.qq.com/"; } + if (details.url.indexOf(".kugou.com/") != -1) { referer_value = "http://www.kugou.com/"; } + if (details.url.indexOf(".kuwo.cn/") != -1) { referer_value = "http://www.kuwo.cn/"; } + if (details.url.indexOf(".bilibili.com/") != -1) { referer_value = "http://www.bilibili.com/"; replace_origin = false; @@ -74,7 +82,7 @@ function hack_referer_header(details) { }; chrome.webRequest.onBeforeSendHeaders.addListener(hack_referer_header, { - urls: ["*://music.163.com/*", "*://*.xiami.com/*", "*://*.qq.com/*", "*://*.kugou.com/*", "*://*.bilibili.com/*"] + urls: ["*://music.163.com/*", "*://*.xiami.com/*", "*://*.qq.com/*", "*://*.kugou.com/*", "*://*.bilibili.com/*", "*://*.githubusercontent.com/*"] }, ['requestHeaders', 'blocking']); diff --git a/app/listen1_chrome_extension/js/github.js b/app/listen1_chrome_extension/js/github.js index 944a426..b57bf8e 100644 --- a/app/listen1_chrome_extension/js/github.js +++ b/app/listen1_chrome_extension/js/github.js @@ -4,8 +4,18 @@ ngGithub.factory('github', ['$rootScope', function($rootScope) { return { openAuthUrl: function(){ - console.log('openAuthUrl'); - window.open(Github.getOAuthUrl(), '_blank'); + var url=Github.getOAuthUrl(); + if( (typeof chrome) == 'undefined') { + // normal window for link + const {BrowserWindow} = require('electron').remote + let win = new BrowserWindow({width: 1000, height: 670}) + win.on('closed', () => { + win = null + }) + win.loadURL(url); + return; + } + window.open(url, '_blank'); }, getStatusText: function(){ return Github.getStatusText(); @@ -14,7 +24,7 @@ function($rootScope) { return Github.getStatus(); }, updateStatus: function(){ - console.log('github update status'); + // console.log('github update status'); Github.updateStatus(function(newStatus){ $rootScope.$broadcast('github:status', newStatus); }); @@ -63,9 +73,22 @@ ngGithub.provider('gist', { return result; } - function gist2json(gistFiles) { - var jsonString = gistFiles['listen1_backup.json'].content; - return JSON.parse(jsonString); + function gist2json(gistFiles, callback) { + if (!gistFiles['listen1_backup.json'].truncated) { + var jsonString = gistFiles['listen1_backup.json'].content; + return callback(JSON.parse(jsonString)); + } + else { + var url = gistFiles['listen1_backup.json'].raw_url; + var size = gistFiles['listen1_backup.json'].size; + $http({ + method: 'GET', + url: url, + headers:{'Authorization':'token ' + localStorage.getObject("githubOauthAccessKey")}, + }).then(function(res) { + return callback(res.data); + }); + } } function listExistBackup(){ diff --git a/app/listen1_chrome_extension/js/myplaylist.js b/app/listen1_chrome_extension/js/myplaylist.js index a848186..47e96d8 100644 --- a/app/listen1_chrome_extension/js/myplaylist.js +++ b/app/listen1_chrome_extension/js/myplaylist.js @@ -76,10 +76,11 @@ var add_myplaylist = function(playlist_id, track) { if (playlist == null) { return; } + // new track will always insert in beginning of playlist if (Array.isArray(track)) { - playlist.tracks = playlist.tracks.concat(track); + playlist.tracks = track.concat(playlist.tracks); } else { - playlist.tracks.push(track); + playlist.tracks.unshift(track); } // dedupe diff --git a/app/listen1_chrome_extension/js/provider/bilibili.js b/app/listen1_chrome_extension/js/provider/bilibili.js index 14191fe..5f54583 100644 --- a/app/listen1_chrome_extension/js/provider/bilibili.js +++ b/app/listen1_chrome_extension/js/provider/bilibili.js @@ -1,7 +1,6 @@ var bilibili = (function() { 'use strict'; - - function bi_convert_song(song_info) { + function bi_convert_song(song_info) { var track = { 'id': 'bitrack_' + song_info.id, 'title': song_info.title, @@ -15,11 +14,10 @@ var bilibili = (function() { }; return track; } - - var bi_show_playlist = function(url, hm) { + var bi_show_playlist = function(url, hm) { var offset = getParameterByName("offset", url) if (offset == undefined) { offset = 0; } - var page = offset / 20; + var page = offset / 20 + 1; var target_url = 'https://www.bilibili.com/audio/music-service-c/web/menu/hit?ps=20&pn=' + page return { success: function(fn) { @@ -40,24 +38,20 @@ var bilibili = (function() { } }; } - - var bi_get_playlist = function(url, hm, se) { + var bi_get_playlist = function(url, hm, se) { var list_id = getParameterByName('list_id', url).split('_').pop(); var target_url = 'https://www.bilibili.com/audio/music-service-c/web/menu/info?sid=' + list_id; - - return { + return { success: function(fn) { hm.get(target_url).then(function(response) { var data = response.data.data; - - var info = { + var info = { 'cover_img_url': data.cover, 'title': data.title, 'id': 'biplaylist_' + list_id, 'source_url': 'https://www.bilibili.com/audio/am' + list_id }; - - var target_url = 'https://www.bilibili.com/audio/music-service-c/web/song/of-menu?pn=1&ps=100&sid=' + list_id; + var target_url = 'https://www.bilibili.com/audio/music-service-c/web/song/of-menu?pn=1&ps=100&sid=' + list_id; hm.get(target_url).then(function(response) { var data = response.data.data.data; var tracks = []; @@ -71,8 +65,7 @@ var bilibili = (function() { } }; } - - var bi_album = function(url, hm, se) { + var bi_album = function(url, hm, se) { return { success: function(fn) { return fn({"tracks": [], "info": {}}); @@ -81,39 +74,31 @@ var bilibili = (function() { var target_url = '' hm.get(target_url).then(function(response) { var data = response.data; - - var info = {}; - - var tracks = []; + var info = {}; + var tracks = []; return fn({"tracks": tracks, "info": info}); }); } }; } - - var bi_artist = function (url, hm, se) { + var bi_artist = function (url, hm, se) { return { success: function(fn) { var artist_id = getParameterByName('list_id', url).split('_').pop(); - - var target_url = 'https://space.bilibili.com/ajax/member/GetInfo' - - hm.post(target_url, $.param({mid: artist_id}), {headers: {'Content-Type': 'application/x-www-form-urlencoded'}}) + var target_url = 'https://space.bilibili.com/ajax/member/GetInfo' + hm.post(target_url, $.param({mid: artist_id}), {headers: {'Content-Type': 'application/x-www-form-urlencoded'}}) .then(function(response) { var data = response.data.data; - - var info = { + var info = { 'cover_img_url': data.face, 'title': data.name, 'id': 'biartist_' + artist_id, 'source_url': 'https://space.bilibili.com/' + artist_id + '/#/audio' }; - - target_url = 'https://api.bilibili.com/audio/music-service-c/web/song/upper?pn=1&ps=0&order=2&uid=' + artist_id + target_url = 'https://api.bilibili.com/audio/music-service-c/web/song/upper?pn=1&ps=0&order=2&uid=' + artist_id hm.get(target_url).then(function(response) { var data = response.data.data.data; - - var tracks = []; + var tracks = []; $.each(data, function(index, item) { var track = bi_convert_song(item); tracks.push(track); @@ -124,8 +109,7 @@ var bilibili = (function() { } }; } - - var bi_parse_url = function(url) { + var bi_parse_url = function(url) { var result = undefined; var match = /\/\/www.bilibili.com\/audio\/am([0-9]+)/.exec(url); if (match != null) { @@ -134,12 +118,10 @@ var bilibili = (function() { } return result; } - - var bi_bootstrap_track = function(sound, track, success, failure, hm, se) { + var bi_bootstrap_track = function(sound, track, success, failure, hm, se) { var song_id = track.id.slice('bitrack_'.length); var target_url = 'https://www.bilibili.com/audio/music-service-c/web/url?sid=' + song_id; - - hm.get(target_url).then(function(response) { + hm.get(target_url).then(function(response) { var data = response.data; if (data.code == 0) { sound.url = data.data.cdns[0]; @@ -149,8 +131,7 @@ var bilibili = (function() { } }); } - - var bi_search = function(url, hm, se) { + var bi_search = function(url, hm, se) { return { success: function(fn) { var keyword = getParameterByName('keywords', url); @@ -180,8 +161,7 @@ var bilibili = (function() { } }; } - - var bi_lyric = function (url, hm, se) { + var bi_lyric = function (url, hm, se) { var track_id = getParameterByName('track_id', url).split('_').pop(); var lyric_url = getParameterByName('lyric_url', url); return { @@ -193,8 +173,7 @@ var bilibili = (function() { } }; } - - var get_playlist = function(url, hm, se) { + var get_playlist = function(url, hm, se) { var list_id = getParameterByName('list_id', url).split('_')[0]; if (list_id == 'biplaylist') { return bi_get_playlist(url, hm, se); @@ -206,8 +185,7 @@ var bilibili = (function() { return bi_artist(url, hm, se); } } - - return { + return { show_playlist: bi_show_playlist, get_playlist: get_playlist, parse_url: bi_parse_url, @@ -215,4 +193,4 @@ var bilibili = (function() { search: bi_search, lyric: bi_lyric, }; -})(); +})(); \ No newline at end of file diff --git a/app/listen1_chrome_extension/js/provider/kugou.js b/app/listen1_chrome_extension/js/provider/kugou.js index 1898651..9c48ab2 100644 --- a/app/listen1_chrome_extension/js/provider/kugou.js +++ b/app/listen1_chrome_extension/js/provider/kugou.js @@ -110,13 +110,23 @@ var kugou = (function() { track['artist'] = data.singerId == 0 ? '未知' : data.singerName; track['artist_id'] = 'kgartist_' + data.singerId; - track['img_url'] = data.imgUrl.replace('{size}', '400'); + if (data.imgUrl !== undefined) { + track['img_url'] = data.imgUrl.replace('{size}', '400'); + } + else { + // track['img_url'] = data.imgUrl.replace('{size}', '400'); + } // Fix album target_url = 'http://mobilecdnbj.kugou.com/api/v3/album/info?albumid=' + item.album_id; hm.get(target_url).then(function(response){ var data = response.data; - track['album'] = data.status ? data.data.albumname : ''; + if (data.status && data.data!= undefined) { + track['album'] = data.data.albumname; + } + else { + track['album'] = ''; + } return callback(null, track); }); }); @@ -179,7 +189,12 @@ var kugou = (function() { transformResponse: undefined }).then(function(response){ var data = response.data; data = JSON.parse(data); - track['album'] = data.status ? data.data.albumname : ''; + if (data.status && data.data!= undefined) { + track['album'] = data.data.albumname; + } + else { + track['album'] = ''; + } hm({ url: target_url, method: 'GET', transformResponse: undefined }).then(function(response){ @@ -226,22 +241,29 @@ var kugou = (function() { } }; } - + function getTimestampString(){ + return (new Date).getTime().toString(); + } + function getRandomIntString(){ + return (Math.random()*100).toString().replace(/\D/g,''); + } var kg_bootstrap_track = function(sound, track, success, failure, hm, se) { - var target_url = 'http://trackercdnbj.kugou.com/i/v2/?cmd=23&pid=1&behavior=download'; + var target_url = 'https://wwwapi.kugou.com/yy/index.php?r=play/getdata'; + var jQueryHeader = 'jQuery1910' + getRandomIntString() + '_' + getTimestampString(); + var song_id = track.id.slice('kgtrack_'.length); - var key = MD5(song_id + 'kgcloudv2'); - target_url = target_url + '&hash=' + song_id + '&key=' + key; + + target_url = target_url + '&callback=' + jQueryHeader + '&hash=' + song_id + '&_=' + getTimestampString(); hm({ url: target_url, method: 'GET', transformResponse: undefined }).then(function(response){ - var data = response.data; + var data = response.data.slice(jQueryHeader.length+1, response.data.length-2); data = JSON.parse(data); if (data.status == '1') { - sound.url = data.url; + sound.url = data.data.play_url; success(); } else { failure(); diff --git a/app/listen1_chrome_extension/js/provider/netease.js b/app/listen1_chrome_extension/js/provider/netease.js index 7725663..bb0b7d8 100644 --- a/app/listen1_chrome_extension/js/provider/netease.js +++ b/app/listen1_chrome_extension/js/provider/netease.js @@ -4,9 +4,9 @@ var netease = (function() { var ne_show_playlist = function(url, hm) { var order = "hot" - var offset = getParameterByName('offset', url) + var offset = getParameterByName('offset',url) - if (offset != null) { + if (offset != null) { var target_url = 'http://music.163.com/discover/playlist/?order=' + order + '&limit=35&offset=' + offset; } else { var target_url = 'http://music.163.com/discover/playlist/?order=' + order; @@ -18,9 +18,9 @@ var netease = (function() { hm.get(target_url).then(function(response) { var data = response.data; data = $.parseHTML(data); - $(data).find('.m-cvrlst li').each(function() { + $(data).find('.m-cvrlst li').each(function(){ var default_playlist = { - 'cover_img_url': '', + 'cover_img_url' : '', 'title': '', 'id': '', 'source_url': '' @@ -28,12 +28,12 @@ var netease = (function() { default_playlist.cover_img_url = $(this).find('img')[0].src; default_playlist.title = $(this).find('div a')[0].title; var url = $(this).find('div a')[0].href; - var list_id = getParameterByName('id', url); + var list_id = getParameterByName('id',url); default_playlist.id = 'neplaylist_' + list_id; default_playlist.source_url = 'http://music.163.com/#/playlist?id=' + list_id; result.push(default_playlist); }); - return fn({ "result": result }); + return fn({"result":result}); }); } }; @@ -42,7 +42,7 @@ var netease = (function() { function _create_secret_key(size) { var result = []; var choice = '012345679abcdef'.split(''); - for (var i = 0; i < size; i++) { + for (var i=0; i= 0) && (song.fee != 4)); } - + var ne_search = function(url, hm, se) { // use chrome extension to modify referer. var target_url = 'http://music.163.com/api/search/pc'; @@ -235,7 +272,7 @@ var netease = (function() { var curpage = getParameterByName('curpage', url); var req_data = { 's': keyword, - 'offset': 20 * (curpage - 1), + 'offset': 20*(curpage-1), 'limit': 20, 'type': 1 }; @@ -246,7 +283,7 @@ var netease = (function() { method: 'POST', data: se(req_data), headers: { - 'Content-Type': 'application/x-www-form-urlencoded' + 'Content-Type': 'application/x-www-form-urlencoded' } }).then(function(response) { var data = response.data; @@ -266,12 +303,13 @@ var netease = (function() { }; if (!is_playable(song_info)) { default_track.disabled = true; - } else { + } + else { default_track.disabled = false; } tracks.push(default_track); }); - return fn({ "result": tracks, "total": data.result.songCount }); + return fn({"result":tracks,"total":data.result.songCount}); }); } }; @@ -311,14 +349,15 @@ var netease = (function() { 'img_url': song_info.album.picUrl, 'url': 'netrack_' + song_info.id }; - if (!is_playable(song_info)) { + if (!is_playable(song_info)) { default_track.disabled = true; - } else { + } + else { default_track.disabled = false; } tracks.push(default_track); }); - return fn({ "tracks": tracks, "info": info }); + return fn({"tracks":tracks, "info":info}); }); } }; @@ -359,12 +398,13 @@ var netease = (function() { }; if (!is_playable(song_info)) { default_track.disabled = true; - } else { + } + else { default_track.disabled = false; } tracks.push(default_track); }); - return fn({ "tracks": tracks, "info": info }); + return fn({"tracks":tracks, "info":info}); }); } }; @@ -389,7 +429,7 @@ var netease = (function() { method: 'POST', data: se(data), headers: { - 'Content-Type': 'application/x-www-form-urlencoded' + 'Content-Type': 'application/x-www-form-urlencoded' } }).then(function(response) { var data = response.data; @@ -397,7 +437,7 @@ var netease = (function() { if (data.lrc != null) { lrc = data.lrc.lyric; } - return fn({ "lyric": lrc }); + return fn({"lyric":lrc}); }); } }; @@ -405,35 +445,34 @@ var netease = (function() { var ne_parse_url = function(url) { var result = undefined; - url = url.replace('music.163.com/#/my/m/music/playlist?', 'music.163.com/#/playlist?'); - if (url.search('//music.163.com/#/m/playlist') != -1 || url.search('//music.163.com/#/playlist') != -1) { - result = { 'type': 'playlist', 'id': 'neplaylist_' + getParameterByName('id', url) }; - } else if (url.search('//music.163.com/playlist') != -1) { - result = { 'type': 'playlist', 'id': 'neplaylist_' + getParameterByName('id', url) }; + url = url.replace('music.163.com/#/my/m/music/playlist?','music.163.com/#/playlist?'); + if (url.search('//music.163.com/#/m/playlist') != -1 || url.search('//music.163.com/#/playlist') != -1 || url.search('//music.163.com/playlist') != -1) { + result = {'type': 'playlist', 'id': 'neplaylist_' + getParameterByName('id', url)}; } return result; } - var get_playlist = function(url, hm, se) { - var list_id = getParameterByName('list_id', url).split('_')[0]; - if (list_id == 'neplaylist') { - return ne_get_playlist(url, hm, se); - } - if (list_id == 'nealbum') { - return ne_album(url, hm, se); - } - if (list_id == 'neartist') { - return ne_artist(url, hm, se); - } +var get_playlist = function(url, hm, se) { + var list_id = getParameterByName('list_id', url).split('_')[0]; + if (list_id == 'neplaylist') { + return ne_get_playlist(url, hm, se); + } + if (list_id == 'nealbum') { + return ne_album(url, hm, se); } + if (list_id == 'neartist') { + return ne_artist(url, hm, se); + } +} + +return { + show_playlist: ne_show_playlist, + get_playlist: get_playlist, + parse_url: ne_parse_url, + bootstrap_track: ne_bootstrap_track, + search: ne_search, + lyric: ne_lyric, +}; - return { - show_playlist: ne_show_playlist, - get_playlist: get_playlist, - parse_url: ne_parse_url, - bootstrap_track: ne_bootstrap_track, - search: ne_search, - lyric: ne_lyric, - }; +})(); -})(); \ No newline at end of file diff --git a/app/listen1_chrome_extension/js/provider/qq.js b/app/listen1_chrome_extension/js/provider/qq.js index 99ba814..498647d 100644 --- a/app/listen1_chrome_extension/js/provider/qq.js +++ b/app/listen1_chrome_extension/js/provider/qq.js @@ -309,6 +309,16 @@ var qq = (function() { var playlist_id = match[1]; result = {'type': 'playlist', 'id': 'qqplaylist_' + playlist_id}; } + match = /\/\/y.qq.com\/n\/yqq\/playsquare\/([0-9]+)/.exec(url); + if (match != null) { + var playlist_id = match[1]; + result = {'type': 'playlist', 'id': 'qqplaylist_' + playlist_id}; + } + match = /\/\/y.qq.com\/n\/m\/detail\/taoge\/index.html\?id=([0-9]+)/.exec(url); + if (match != null) { + var playlist_id = match[1]; + result = {'type': 'playlist', 'id': 'qqplaylist_' + playlist_id}; + } return result; } diff --git a/app/listen1_chrome_extension/js/provider/xiami.js b/app/listen1_chrome_extension/js/provider/xiami.js index 4e8baf0..b583afa 100644 --- a/app/listen1_chrome_extension/js/provider/xiami.js +++ b/app/listen1_chrome_extension/js/provider/xiami.js @@ -43,24 +43,49 @@ var xiami = (function() { return s; } - function xm_ensure_cookie(callback){ + function xm_get_token(callback) { var domain = 'https://www.xiami.com'; var name = 'xm_sg_tk'; - chrome.cookies.get({"url": domain, "name": name}, function(cookie) { - if (cookie == null) { - var xhr = new XMLHttpRequest(); + var cookieProvider = null; + if (typeof chrome !== 'undefined') { + cookieProvider = chrome; + cookieProvider.cookies.get({url: domain, name:name}, function(cookie) { + if (cookie == null) { + return callback(''); + } + return callback(cookie.value); + }); + } + else { + var remote = require('electron').remote; + cookieProvider = remote.session.defaultSession; + cookieProvider.cookies.get({domain: '.xiami.com', name:name}, function(err, cookie) { + if (cookie.length == 0) { + return callback(''); + } + return callback(cookie[0].value); + }); + } - xhr.open("GET", "https://www.xiami.com", false); - xhr.send(); + } - var result = xhr.responseText; - chrome.cookies.get({"url": domain, "name": name}, function(cookie) { - callback(cookie.value); - }); - } - else { - callback(cookie.value); - } + function xm_cookie_get(hm, api, params, callback) { + xm_get_token(function(token){ + var url = xm_get_api_url(api, params, token); + hm.get(url).then(function(response) { + if (response.data.code == "SG_TOKEN_EMPTY" || response.data.code == "SG_TOKEN_EXPIRED"||response.data.code == "SG_INVALID") { + // token expire, refetch token and start get url + xm_get_token(function(token){ + var url = xm_get_api_url(api, params, token); + hm.get(url).then(function(response) { + callback(response); + }); + }); + } + else { + callback(response); + } + }); }); } @@ -72,6 +97,10 @@ var xiami = (function() { return encodeURI(baseUrl + api + '?_q=' + params_string + '&_s=' + sign); } + function xm_get_low_quality_img_url(url) { + return url + '?x-oss-process=image/resize,m_fill,limit_0,s_330/quality,q_80'; + } + var xm_show_playlist = function(url, hm) { var offset = getParameterByName("offset",url); var page = offset/30 + 1; @@ -80,28 +109,25 @@ var xiami = (function() { return { success: function(fn) { var result = []; - xm_ensure_cookie(function(token){ - var api = '/api/list/collect'; - var params = {"pagingVO":{"page":page,"pageSize":pageSize},"dataType":"system"}; - var url = xm_get_api_url(api, params, token); - hm.get(url).then(function(response) { - for(var i=0; i 7 and WebViews may allow multiple Audio() instances. + html5Test: /^(probably|maybe)$/i, // HTML5 Audio() format support test. Use /^probably$/i; if you want to be more conservative. + preferFlash: false, // overrides useHTML5audio, will use Flash for MP3/MP4/AAC if present. Potential option if HTML5 playback with these formats is quirky. + noSWFCache: false, // if true, appends ?ts={date} to break aggressive SWF caching. + idPrefix: 'sound' // if an id is not provided to createSound(), this prefix is used for generated IDs - 'sound0', 'sound1' etc. + + }; + + this.defaultOptions = { + /** - * The SoundManager constructor. - * - * @constructor - * @param {string} smURL Optional: Path to SWF files - * @param {string} smID Optional: The ID to use for the SWF container element - * @this {SoundManager} - * @return {SoundManager} The new SoundManager instance + * the default configuration for sound objects made with createSound() and related methods + * eg., volume, auto-load behaviour and so forth */ - function SoundManager(smURL, smID) { - /** - * soundManager configuration options list - * defines top-level configuration properties to be applied to the soundManager instance (eg. soundManager.flashVersion) - * to set these properties, use the setup() method - eg., soundManager.setup({url: '/swf/', flashVersion: 9}) - */ - this.setupOptions = { - 'url': (smURL || null), // path (directory) where SoundManager 2 SWFs exist, eg., /path/to/swfs/ - 'flashVersion': 8, // flash build to use (8 or 9.) Some API features require 9. - 'debugMode': true, // enable debugging output (console.log() with HTML fallback) - 'debugFlash': false, // enable debugging output inside SWF, troubleshoot Flash/browser issues - 'useConsole': true, // use console.log() if available (otherwise, writes to #soundmanager-debug element) - 'consoleOnly': true, // if console is being used, do not create/write to #soundmanager-debug - 'waitForWindowLoad': false, // force SM2 to wait for window.onload() before trying to call soundManager.onload() - 'bgColor': '#ffffff', // SWF background color. N/A when wmode = 'transparent' - 'useHighPerformance': false, // position:fixed flash movie can help increase js/flash speed, minimize lag - 'flashPollingInterval': null, // msec affecting whileplaying/loading callback frequency. If null, default of 50 msec is used. - 'html5PollingInterval': null, // msec affecting whileplaying() for HTML5 audio, excluding mobile devices. If null, native HTML5 update events are used. - 'flashLoadTimeout': 1000, // msec to wait for flash movie to load before failing (0 = infinity) - 'wmode': null, // flash rendering mode - null, 'transparent', or 'opaque' (last two allow z-index to work) - 'allowScriptAccess': 'always', // for scripting the SWF (object/embed property), 'always' or 'sameDomain' - 'useFlashBlock': false, // *requires flashblock.css, see demos* - allow recovery from flash blockers. Wait indefinitely and apply timeout CSS to SWF, if applicable. - 'useHTML5Audio': true, // use HTML5 Audio() where API is supported (most Safari, Chrome versions), Firefox (no MP3/MP4.) Ideally, transparent vs. Flash API where possible. - 'html5Test': /^(probably|maybe)$/i, // HTML5 Audio() format support test. Use /^probably$/i; if you want to be more conservative. - 'preferFlash': false, // overrides useHTML5audio, will use Flash for MP3/MP4/AAC if present. Potential option if HTML5 playback with these formats is quirky. - 'noSWFCache': false, // if true, appends ?ts={date} to break aggressive SWF caching. - 'idPrefix': 'sound' // if an id is not provided to createSound(), this prefix is used for generated IDs - 'sound0', 'sound1' etc. - }; - this.defaultOptions = { - /** - * the default configuration for sound objects made with createSound() and related methods - * eg., volume, auto-load behaviour and so forth - */ - 'autoLoad': false, // enable automatic loading (otherwise .load() will be called on demand with .play(), the latter being nicer on bandwidth - if you want to .load yourself, you also can) - 'autoPlay': false, // enable playing of file as soon as possible (much faster if "stream" is true) - 'from': null, // position to start playback within a sound (msec), default = beginning - 'loops': 1, // how many times to repeat the sound (position will wrap around to 0, setPosition() will break out of loop when >0) - 'onid3': null, // callback function for "ID3 data is added/available" - 'onload': null, // callback function for "load finished" - 'whileloading': null, // callback function for "download progress update" (X of Y bytes received) - 'onplay': null, // callback for "play" start - 'onpause': null, // callback for "pause" - 'onresume': null, // callback for "resume" (pause toggle) - 'whileplaying': null, // callback during play (position update) - 'onposition': null, // object containing times and function callbacks for positions of interest - 'onstop': null, // callback for "user stop" - 'onfailure': null, // callback function for when playing fails - 'onfinish': null, // callback function for "sound finished playing" - 'multiShot': true, // let sounds "restart" or layer on top of each other when played multiple times, rather than one-shot/one at a time - 'multiShotEvents': false, // fire multiple sound events (currently onfinish() only) when multiShot is enabled - 'position': null, // offset (milliseconds) to seek to within loaded sound data. - 'pan': 0, // "pan" settings, left-to-right, -100 to 100 - 'stream': true, // allows playing before entire file has loaded (recommended) - 'to': null, // position to end playback within a sound (msec), default = end - 'type': null, // MIME-like hint for file pattern / canPlay() tests, eg. audio/mp3 - 'usePolicyFile': false, // enable crossdomain.xml request for audio on remote domains (for ID3/waveform access) - 'volume': 100 // self-explanatory. 0-100, the latter being the max. - }; - this.flash9Options = { - /** - * flash 9-only options, - * merged into defaultOptions if flash 9 is being used - */ - 'isMovieStar': null, // "MovieStar" MPEG4 audio mode. Null (default) = auto detect MP4, AAC etc. based on URL. true = force on, ignore URL - 'usePeakData': false, // enable left/right channel peak (level) data - 'useWaveformData': false, // enable sound spectrum (raw waveform data) - NOTE: May increase CPU load. - 'useEQData': false, // enable sound EQ (frequency spectrum data) - NOTE: May increase CPU load. - 'onbufferchange': null, // callback for "isBuffering" property change - 'ondataerror': null // callback for waveform/eq data access error (flash playing audio in other tabs/domains) - }; - this.movieStarOptions = { - /** - * flash 9.0r115+ MPEG4 audio options, - * merged into defaultOptions if flash 9+movieStar mode is enabled - */ - 'bufferTime': 3, // seconds of data to buffer before playback begins (null = flash default of 0.1 seconds - if AAC playback is gappy, try increasing.) - 'serverURL': null, // rtmp: FMS or FMIS server to connect to, required when requesting media via RTMP or one of its variants - 'onconnect': null, // rtmp: callback for connection to flash media server - 'duration': null // rtmp: song duration (msec) - }; - this.audioFormats = { - /** - * determines HTML5 support + flash requirements. - * if no support (via flash and/or HTML5) for a "required" format, SM2 will fail to start. - * flash fallback is used for MP3 or MP4 if HTML5 can't play it (or if preferFlash = true) - */ - 'mp3': { - 'type': ['audio/mpeg; codecs="mp3"', 'audio/mpeg', 'audio/mp3', 'audio/MPA', 'audio/mpa-robust'], - 'required': true - }, - 'mp4': { - 'related': ['aac', 'm4a', 'm4b'], // additional formats under the MP4 container - 'type': ['audio/mp4; codecs="mp4a.40.2"', 'audio/aac', 'audio/x-m4a', 'audio/MP4A-LATM', 'audio/mpeg4-generic'], - 'required': false - }, - 'ogg': { - 'type': ['audio/ogg; codecs=vorbis'], - 'required': false - }, - 'opus': { - 'type': ['audio/ogg; codecs=opus', 'audio/opus'], - 'required': false - }, - 'wav': { - 'type': ['audio/wav; codecs="1"', 'audio/wav', 'audio/wave', 'audio/x-wav'], - 'required': false - } - }; - // HTML attributes (id + class names) for the SWF container - this.movieID = 'sm2-container'; - this.id = (smID || 'sm2movie'); - this.debugID = 'soundmanager-debug'; - this.debugURLParam = /([#?&])debug=1/i; - // dynamic attributes - this.versionNumber = 'V2.97a.20140901'; - this.version = null; - this.movieURL = null; - this.altURL = null; - this.swfLoaded = false; - this.enabled = false; - this.oMC = null; - this.sounds = {}; - this.soundIDs = []; - this.muted = false; - this.didFlashBlock = false; - this.filePattern = null; - this.filePatterns = { - 'flash8': /\.mp3(\?.*)?$/i, - 'flash9': /\.mp3(\?.*)?$/i - }; - // support indicators, set at init - this.features = { - 'buffering': false, - 'peakData': false, - 'waveformData': false, - 'eqData': false, - 'movieStar': false - }; - // flash sandbox info, used primarily in troubleshooting - this.sandbox = { - // - 'type': null, - 'types': { - 'remote': 'remote (domain-based) rules', - 'localWithFile': 'local with file access (no internet access)', - 'localWithNetwork': 'local with network (internet access only, no local access)', - 'localTrusted': 'local, trusted (local+internet access)' - }, - 'description': null, - 'noRemote': null, - 'noLocal': null - // - }; - /** - * format support (html5/flash) - * stores canPlayType() results based on audioFormats. - * eg. { mp3: boolean, mp4: boolean } - * treat as read-only. - */ - this.html5 = { - 'usingFlash': null // set if/when flash fallback is needed - }; - // file type support hash - this.flash = {}; - // determined at init time - this.html5Only = false; - // used for special cases (eg. iPad/iPhone/palm OS?) - this.ignoreFlash = false; - /** - * a few private internals (OK, a lot. :D) - */ - var SMSound, - sm2 = this, - globalHTML5Audio = null, - flash = null, - sm = 'soundManager', - smc = sm + ': ', - h5 = 'HTML5::', - id, ua = navigator.userAgent, - wl = window.location.href.toString(), - doc = document, - doNothing, setProperties, init, fV, on_queue = [], - debugOpen = true, - debugTS, didAppend = false, - appendSuccess = false, - didInit = false, - disabled = false, - windowLoaded = false, - _wDS, wdCount = 0, - initComplete, mixin, assign, extraOptions, addOnEvent, processOnEvents, initUserOnload, delayWaitForEI, waitForEI, rebootIntoHTML5, setVersionInfo, handleFocus, strings, initMovie, preInit, domContentLoaded, winOnLoad, didDCLoaded, getDocument, createMovie, catchError, setPolling, initDebug, debugLevels = ['log', 'info', 'warn', 'error'], - defaultFlashVersion = 8, - disableObject, failSafely, normalizeMovieURL, oRemoved = null, - oRemovedHTML = null, - str, flashBlockHandler, getSWFCSS, swfCSS, toggleDebug, loopFix, policyFix, complain, idCheck, waitingForEI = false, - initPending = false, - startTimer, stopTimer, timerExecute, h5TimerCount = 0, - h5IntervalTimer = null, - parseURL, messages = [], - canIgnoreFlash, needsFlash = null, - featureCheck, html5OK, html5CanPlay, html5Ext, html5Unload, domContentLoadedIE, testHTML5, event, slice = Array.prototype.slice, - useGlobalHTML5Audio = false, - lastGlobalHTML5URL, hasFlash, detectFlash, badSafariFix, html5_events, showSupport, flushMessages, wrapCallback, idCounter = 0, - is_iDevice = ua.match(/(ipad|iphone|ipod)/i), - isAndroid = ua.match(/android/i), - isIE = ua.match(/msie/i), - isWebkit = ua.match(/webkit/i), - isSafari = (ua.match(/safari/i) && !ua.match(/chrome/i)), - isOpera = (ua.match(/opera/i)), - mobileHTML5 = (ua.match(/(mobile|pre\/|xoom)/i) || is_iDevice || isAndroid), - isBadSafari = (!wl.match(/usehtml5audio/i) && !wl.match(/sm2\-ignorebadua/i) && isSafari && !ua.match(/silk/i) && ua.match(/OS X 10_6_([3-7])/i)), // Safari 4 and 5 (excluding Kindle Fire, "Silk") occasionally fail to load/play HTML5 audio on Snow Leopard 10.6.3 through 10.6.7 due to bug(s) in QuickTime X and/or other underlying frameworks. :/ Confirmed bug. https://bugs.webkit.org/show_bug.cgi?id=32159 - hasConsole = (window.console !== _undefined && console.log !== _undefined), - isFocused = (doc.hasFocus !== _undefined ? doc.hasFocus() : null), - tryInitOnFocus = (isSafari && (doc.hasFocus === _undefined || !doc.hasFocus())), - okToDisable = !tryInitOnFocus, - flashMIME = /(mp3|mp4|mpa|m4a|m4b)/i, - msecScale = 1000, - emptyURL = 'about:blank', // safe URL to unload, or load nothing from (flash 8 + most HTML5 UAs) - emptyWAV = 'data:audio/wave;base64,/UklGRiYAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQIAAAD//w==', // tiny WAV for HTML5 unloading - overHTTP = (doc.location ? doc.location.protocol.match(/http/i) : null), - http = (!overHTTP ? 'http:/' + '/' : ''), - // mp3, mp4, aac etc. - netStreamMimeTypes = /^\s*audio\/(?:x-)?(?:mpeg4|aac|flv|mov|mp4||m4v|m4a|m4b|mp4v|3gp|3g2)\s*(?:$|;)/i, - // Flash v9.0r115+ "moviestar" formats - netStreamTypes = ['mpeg4', 'aac', 'flv', 'mov', 'mp4', 'm4v', 'f4v', 'm4a', 'm4b', 'mp4v', '3gp', '3g2'], - netStreamPattern = new RegExp('\\.(' + netStreamTypes.join('|') + ')(\\?.*)?$', 'i'); - this.mimePattern = /^\s*audio\/(?:x-)?(?:mp(?:eg|3))\s*(?:$|;)/i; // default mp3 set - // use altURL if not "online" - this.useAltURL = !overHTTP; - swfCSS = { - 'swfBox': 'sm2-object-box', - 'swfDefault': 'movieContainer', - 'swfError': 'swf_error', // SWF loaded, but SM2 couldn't start (other error) - 'swfTimedout': 'swf_timedout', - 'swfLoaded': 'swf_loaded', - 'swfUnblocked': 'swf_unblocked', // or loaded OK - 'sm2Debug': 'sm2_debug', - 'highPerf': 'high_performance', - 'flashDebug': 'flash_debug' - }; - /** - * basic HTML5 Audio() support test - * try...catch because of IE 9 "not implemented" nonsense - * https://github.com/Modernizr/Modernizr/issues/224 - */ - this.hasHTML5 = (function() { - try { - // new Audio(null) for stupid Opera 9.64 case, which throws not_enough_arguments exception otherwise. - return(Audio !== _undefined && (isOpera && opera !== _undefined && opera.version() < 10 ? new Audio(null) : new Audio()).canPlayType !== _undefined); - } catch(e) { - return false; - } - }()); - /** - * Public SoundManager API - * ----------------------- - */ - /** - * Configures top-level soundManager properties. - * - * @param {object} options Option parameters, eg. { flashVersion: 9, url: '/path/to/swfs/' } - * onready and ontimeout are also accepted parameters. call soundManager.setup() to see the full list. - */ - this.setup = function(options) { - var noURL = (!sm2.url); - // warn if flash options have already been applied - if(options !== _undefined && didInit && needsFlash && sm2.ok() && (options.flashVersion !== _undefined || options.url !== _undefined || options.html5Test !== _undefined)) { - complain(str('setupLate')); - } - // TODO: defer: true? - assign(options); - // special case 1: "Late setup". SM2 loaded normally, but user didn't assign flash URL eg., setup({url:...}) before SM2 init. Treat as delayed init. - if(options) { - if(noURL && didDCLoaded && options.url !== _undefined) { - sm2.beginDelayedInit(); - } - // special case 2: If lazy-loading SM2 (DOMContentLoaded has already happened) and user calls setup() with url: parameter, try to init ASAP. - if(!didDCLoaded && options.url !== _undefined && doc.readyState === 'complete') { - setTimeout(domContentLoaded, 1); - } - } - return sm2; - }; - this.ok = function() { - return(needsFlash ? (didInit && !disabled) : (sm2.useHTML5Audio && sm2.hasHTML5)); - }; - this.supported = this.ok; // legacy - this.getMovie = function(smID) { - // safety net: some old browsers differ on SWF references, possibly related to ExternalInterface / flash version - return id(smID) || doc[smID] || window[smID]; - }; - /** - * Creates a SMSound sound object instance. - * - * @param {object} oOptions Sound options (at minimum, id and url parameters are required.) - * @return {object} SMSound The new SMSound object. - */ - this.createSound = function(oOptions, _url) { - var cs, cs_string, options, oSound = null; - // - cs = sm + '.createSound(): '; - cs_string = cs + str(!didInit ? 'notReady' : 'notOK'); - // - if(!didInit || !sm2.ok()) { - complain(cs_string); - return false; - } - if(_url !== _undefined) { - // function overloading in JS! :) ..assume simple createSound(id, url) use case - oOptions = { - 'id': oOptions, - 'url': _url - }; - } - // inherit from defaultOptions - options = mixin(oOptions); - options.url = parseURL(options.url); - // generate an id, if needed. - if(options.id === undefined) { - options.id = sm2.setupOptions.idPrefix + (idCounter++); - } - // - if(options.id.toString().charAt(0).match(/^[0-9]$/)) { - sm2._wD(cs + str('badID', options.id), 2); - } - sm2._wD(cs + options.id + (options.url ? ' (' + options.url + ')' : ''), 1); - // - if(idCheck(options.id, true)) { - sm2._wD(cs + options.id + ' exists', 1); - return sm2.sounds[options.id]; - } + autoLoad: false, // enable automatic loading (otherwise .load() will be called on demand with .play(), the latter being nicer on bandwidth - if you want to .load yourself, you also can) + autoPlay: false, // enable playing of file as soon as possible (much faster if "stream" is true) + from: null, // position to start playback within a sound (msec), default = beginning + loops: 1, // how many times to repeat the sound (position will wrap around to 0, setPosition() will break out of loop when >0) + onid3: null, // callback function for "ID3 data is added/available" + onerror: null, // callback function for "load failed" (or, playback/network/decode error under HTML5.) + onload: null, // callback function for "load finished" + whileloading: null, // callback function for "download progress update" (X of Y bytes received) + onplay: null, // callback for "play" start + onpause: null, // callback for "pause" + onresume: null, // callback for "resume" (pause toggle) + whileplaying: null, // callback during play (position update) + onposition: null, // object containing times and function callbacks for positions of interest + onstop: null, // callback for "user stop" + onfinish: null, // callback function for "sound finished playing" + multiShot: true, // let sounds "restart" or layer on top of each other when played multiple times, rather than one-shot/one at a time + multiShotEvents: false, // fire multiple sound events (currently onfinish() only) when multiShot is enabled + position: null, // offset (milliseconds) to seek to within loaded sound data. + pan: 0, // "pan" settings, left-to-right, -100 to 100 + playbackRate: 1, // rate at which to play the sound (HTML5-only) + stream: true, // allows playing before entire file has loaded (recommended) + to: null, // position to end playback within a sound (msec), default = end + type: null, // MIME-like hint for file pattern / canPlay() tests, eg. audio/mp3 + usePolicyFile: false, // enable crossdomain.xml request for audio on remote domains (for ID3/waveform access) + volume: 100 // self-explanatory. 0-100, the latter being the max. + + }; + + this.flash9Options = { + + /** + * flash 9-only options, + * merged into defaultOptions if flash 9 is being used + */ + + onfailure: null, // callback function for when playing fails (Flash 9, MovieStar + RTMP-only) + isMovieStar: null, // "MovieStar" MPEG4 audio mode. Null (default) = auto detect MP4, AAC etc. based on URL. true = force on, ignore URL + usePeakData: false, // enable left/right channel peak (level) data + useWaveformData: false, // enable sound spectrum (raw waveform data) - NOTE: May increase CPU load. + useEQData: false, // enable sound EQ (frequency spectrum data) - NOTE: May increase CPU load. + onbufferchange: null, // callback for "isBuffering" property change + ondataerror: null // callback for waveform/eq data access error (flash playing audio in other tabs/domains) + + }; + + this.movieStarOptions = { + + /** + * flash 9.0r115+ MPEG4 audio options, + * merged into defaultOptions if flash 9+movieStar mode is enabled + */ + + bufferTime: 3, // seconds of data to buffer before playback begins (null = flash default of 0.1 seconds - if AAC playback is gappy, try increasing.) + serverURL: null, // rtmp: FMS or FMIS server to connect to, required when requesting media via RTMP or one of its variants + onconnect: null, // rtmp: callback for connection to flash media server + duration: null // rtmp: song duration (msec) + + }; + + this.audioFormats = { + + /** + * determines HTML5 support + flash requirements. + * if no support (via flash and/or HTML5) for a "required" format, SM2 will fail to start. + * flash fallback is used for MP3 or MP4 if HTML5 can't play it (or if preferFlash = true) + */ + + mp3: { + type: ['audio/mpeg; codecs="mp3"', 'audio/mpeg', 'audio/mp3', 'audio/MPA', 'audio/mpa-robust'], + required: true + }, + + mp4: { + related: ['aac', 'm4a', 'm4b'], // additional formats under the MP4 container + type: ['audio/mp4; codecs="mp4a.40.2"', 'audio/aac', 'audio/x-m4a', 'audio/MP4A-LATM', 'audio/mpeg4-generic'], + required: false + }, + + ogg: { + type: ['audio/ogg; codecs=vorbis'], + required: false + }, + + opus: { + type: ['audio/ogg; codecs=opus', 'audio/opus'], + required: false + }, + + wav: { + type: ['audio/wav; codecs="1"', 'audio/wav', 'audio/wave', 'audio/x-wav'], + required: false + }, + + flac: { + type: ['audio/flac'], + required: false + } + + }; + + // HTML attributes (id + class names) for the SWF container + + this.movieID = 'sm2-container'; + this.id = (smID || 'sm2movie'); + + this.debugID = 'soundmanager-debug'; + this.debugURLParam = /([#?&])debug=1/i; + + // dynamic attributes + + this.versionNumber = 'V2.97a.20170601'; + this.version = null; + this.movieURL = null; + this.altURL = null; + this.swfLoaded = false; + this.enabled = false; + this.oMC = null; + this.sounds = {}; + this.soundIDs = []; + this.muted = false; + this.didFlashBlock = false; + this.filePattern = null; + + this.filePatterns = { + flash8: /\.mp3(\?.*)?$/i, + flash9: /\.mp3(\?.*)?$/i + }; + + // support indicators, set at init + + this.features = { + buffering: false, + peakData: false, + waveformData: false, + eqData: false, + movieStar: false + }; + + // flash sandbox info, used primarily in troubleshooting + + this.sandbox = { + // + type: null, + types: { + remote: 'remote (domain-based) rules', + localWithFile: 'local with file access (no internet access)', + localWithNetwork: 'local with network (internet access only, no local access)', + localTrusted: 'local, trusted (local+internet access)' + }, + description: null, + noRemote: null, + noLocal: null + // + }; + + /** + * format support (html5/flash) + * stores canPlayType() results based on audioFormats. + * eg. { mp3: boolean, mp4: boolean } + * treat as read-only. + */ + + this.html5 = { + usingFlash: null // set if/when flash fallback is needed + }; + + // file type support hash + this.flash = {}; + + // determined at init time + this.html5Only = false; + + // used for special cases (eg. iPad/iPhone/palm OS?) + this.ignoreFlash = false; + + /** + * a few private internals (OK, a lot. :D) + */ + + var SMSound, + sm2 = this, globalHTML5Audio = null, flash = null, sm = 'soundManager', smc = sm + ': ', h5 = 'HTML5::', id, ua = navigator.userAgent, wl = window.location.href.toString(), doc = document, doNothing, setProperties, init, fV, on_queue = [], debugOpen = true, debugTS, didAppend = false, appendSuccess = false, didInit = false, disabled = false, windowLoaded = false, _wDS, wdCount = 0, initComplete, mixin, assign, extraOptions, addOnEvent, processOnEvents, initUserOnload, delayWaitForEI, waitForEI, rebootIntoHTML5, setVersionInfo, handleFocus, strings, initMovie, domContentLoaded, winOnLoad, didDCLoaded, getDocument, createMovie, catchError, setPolling, initDebug, debugLevels = ['log', 'info', 'warn', 'error'], defaultFlashVersion = 8, disableObject, failSafely, normalizeMovieURL, oRemoved = null, oRemovedHTML = null, str, flashBlockHandler, getSWFCSS, swfCSS, toggleDebug, loopFix, policyFix, complain, idCheck, waitingForEI = false, initPending = false, startTimer, stopTimer, timerExecute, h5TimerCount = 0, h5IntervalTimer = null, parseURL, messages = [], + canIgnoreFlash, needsFlash = null, featureCheck, html5OK, html5CanPlay, html5ErrorCodes, html5Ext, html5Unload, domContentLoadedIE, testHTML5, event, slice = Array.prototype.slice, useGlobalHTML5Audio = false, lastGlobalHTML5URL, hasFlash, detectFlash, badSafariFix, html5_events, showSupport, flushMessages, wrapCallback, idCounter = 0, didSetup, msecScale = 1000, + is_iDevice = ua.match(/(ipad|iphone|ipod)/i), isAndroid = ua.match(/android/i), isIE = ua.match(/msie|trident/i), + isWebkit = ua.match(/webkit/i), + isSafari = (ua.match(/safari/i) && !ua.match(/chrome/i)), + isOpera = (ua.match(/opera/i)), + mobileHTML5 = (ua.match(/(mobile|pre\/|xoom)/i) || is_iDevice || isAndroid), + isBadSafari = (!wl.match(/usehtml5audio/i) && !wl.match(/sm2-ignorebadua/i) && isSafari && !ua.match(/silk/i) && ua.match(/OS\sX\s10_6_([3-7])/i)), // Safari 4 and 5 (excluding Kindle Fire, "Silk") occasionally fail to load/play HTML5 audio on Snow Leopard 10.6.3 through 10.6.7 due to bug(s) in QuickTime X and/or other underlying frameworks. :/ Confirmed bug. https://bugs.webkit.org/show_bug.cgi?id=32159 + hasConsole = (window.console !== _undefined && console.log !== _undefined), + isFocused = (doc.hasFocus !== _undefined ? doc.hasFocus() : null), + tryInitOnFocus = (isSafari && (doc.hasFocus === _undefined || !doc.hasFocus())), + okToDisable = !tryInitOnFocus, + flashMIME = /(mp3|mp4|mpa|m4a|m4b)/i, + emptyURL = 'about:blank', // safe URL to unload, or load nothing from (flash 8 + most HTML5 UAs) + emptyWAV = 'data:audio/wave;base64,/UklGRiYAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQIAAAD//w==', // tiny WAV for HTML5 unloading + overHTTP = (doc.location ? doc.location.protocol.match(/http/i) : null), + http = (!overHTTP ? '//' : ''), + // mp3, mp4, aac etc. + netStreamMimeTypes = /^\s*audio\/(?:x-)?(?:mpeg4|aac|flv|mov|mp4|m4v|m4a|m4b|mp4v|3gp|3g2)\s*(?:$|;)/i, + // Flash v9.0r115+ "moviestar" formats + netStreamTypes = ['mpeg4', 'aac', 'flv', 'mov', 'mp4', 'm4v', 'f4v', 'm4a', 'm4b', 'mp4v', '3gp', '3g2'], + netStreamPattern = new RegExp('\\.(' + netStreamTypes.join('|') + ')(\\?.*)?$', 'i'); + + this.mimePattern = /^\s*audio\/(?:x-)?(?:mp(?:eg|3))\s*(?:$|;)/i; // default mp3 set + + // use altURL if not "online" + this.useAltURL = !overHTTP; + + swfCSS = { + swfBox: 'sm2-object-box', + swfDefault: 'movieContainer', + swfError: 'swf_error', // SWF loaded, but SM2 couldn't start (other error) + swfTimedout: 'swf_timedout', + swfLoaded: 'swf_loaded', + swfUnblocked: 'swf_unblocked', // or loaded OK + sm2Debug: 'sm2_debug', + highPerf: 'high_performance', + flashDebug: 'flash_debug' + }; + + /** + * HTML5 error codes, per W3C + * Error code 1, MEDIA_ERR_ABORTED: Client aborted download at user's request. + * Error code 2, MEDIA_ERR_NETWORK: A network error of some description caused the user agent to stop fetching the media resource, after the resource was established to be usable. + * Error code 3, MEDIA_ERR_DECODE: An error of some description occurred while decoding the media resource, after the resource was established to be usable. + * Error code 4, MEDIA_ERR_SRC_NOT_SUPPORTED: Media (audio file) not supported ("not usable.") + * Reference: https://html.spec.whatwg.org/multipage/embedded-content.html#error-codes + */ + html5ErrorCodes = [ + null, + 'MEDIA_ERR_ABORTED', + 'MEDIA_ERR_NETWORK', + 'MEDIA_ERR_DECODE', + 'MEDIA_ERR_SRC_NOT_SUPPORTED' + ]; + + /** + * basic HTML5 Audio() support test + * try...catch because of IE 9 "not implemented" nonsense + * https://github.com/Modernizr/Modernizr/issues/224 + */ + + this.hasHTML5 = (function() { + try { + // new Audio(null) for stupid Opera 9.64 case, which throws not_enough_arguments exception otherwise. + return (Audio !== _undefined && (isOpera && opera !== _undefined && opera.version() < 10 ? new Audio(null) : new Audio()).canPlayType !== _undefined); + } catch(e) { + return false; + } + }()); + + /** + * Public SoundManager API + * ----------------------- + */ + + /** + * Configures top-level soundManager properties. + * + * @param {object} options Option parameters, eg. { flashVersion: 9, url: '/path/to/swfs/' } + * onready and ontimeout are also accepted parameters. call soundManager.setup() to see the full list. + */ + + this.setup = function(options) { + + var noURL = (!sm2.url); + + // warn if flash options have already been applied + + if (options !== _undefined && didInit && needsFlash && sm2.ok() && (options.flashVersion !== _undefined || options.url !== _undefined || options.html5Test !== _undefined)) { + complain(str('setupLate')); + } + + // TODO: defer: true? + + assign(options); + + if (!useGlobalHTML5Audio) { + + if (mobileHTML5) { + + // force the singleton HTML5 pattern on mobile, by default. + if (!sm2.setupOptions.ignoreMobileRestrictions || sm2.setupOptions.forceUseGlobalHTML5Audio) { + messages.push(strings.globalHTML5); + useGlobalHTML5Audio = true; + } + + } else if (sm2.setupOptions.forceUseGlobalHTML5Audio) { + + // only apply singleton HTML5 on desktop if forced. + messages.push(strings.globalHTML5); + useGlobalHTML5Audio = true; + + } + + } + + if (!didSetup && mobileHTML5) { + + if (sm2.setupOptions.ignoreMobileRestrictions) { + + messages.push(strings.ignoreMobile); + + } else { + + // prefer HTML5 for mobile + tablet-like devices, probably more reliable vs. flash at this point. - function make() { - options = loopFix(options); - sm2.sounds[options.id] = new SMSound(options); - sm2.soundIDs.push(options.id); - return sm2.sounds[options.id]; - } - if(html5OK(options)) { - oSound = make(); - sm2._wD(options.id + ': Using HTML5'); - oSound._setup_html5(options); - } else { - if(sm2.html5Only) { - sm2._wD(options.id + ': No HTML5 support for this sound, and no Flash. Exiting.'); - return make(); - } - // TODO: Move HTML5/flash checks into generic URL parsing/handling function. - if(sm2.html5.usingFlash && options.url && options.url.match(/data\:/i)) { - // data: URIs not supported by Flash, either. - sm2._wD(options.id + ': data: URIs not supported via Flash. Exiting.'); - return make(); - } - if(fV > 8) { - if(options.isMovieStar === null) { - // attempt to detect MPEG-4 formats - options.isMovieStar = !! (options.serverURL || (options.type ? options.type.match(netStreamMimeTypes) : false) || (options.url && options.url.match(netStreamPattern))); - } - // - if(options.isMovieStar) { - sm2._wD(cs + 'using MovieStar handling'); - if(options.loops > 1) { - _wDS('noNSLoop'); - } - } - // - } - options = policyFix(options, cs); - oSound = make(); - if(fV === 8) { - flash._createSound(options.id, options.loops || 1, options.usePolicyFile); - } else { - flash._createSound(options.id, options.url, options.usePeakData, options.useWaveformData, options.useEQData, options.isMovieStar, (options.isMovieStar ? options.bufferTime : false), options.loops || 1, options.serverURL, options.duration || null, options.autoPlay, true, options.autoLoad, options.usePolicyFile); - if(!options.serverURL) { - // We are connected immediately - oSound.connected = true; - if(options.onconnect) { - options.onconnect.apply(oSound); - } - } - } - if(!options.serverURL && (options.autoLoad || options.autoPlay)) { - // call load for non-rtmp streams - oSound.load(options); - } - } - // rtmp will play in onconnect - if(!options.serverURL && options.autoPlay) { - oSound.play(); - } - return oSound; - }; - /** - * Destroys a SMSound sound object instance. - * - * @param {string} sID The ID of the sound to destroy - */ - this.destroySound = function(sID, _bFromSound) { - // explicitly destroy a sound before normal page unload, etc. - if(!idCheck(sID)) { - return false; - } - var oS = sm2.sounds[sID], - i; - // Disable all callbacks while the sound is being destroyed - oS._iO = {}; - oS.stop(); - oS.unload(); - for(i = 0; i < sm2.soundIDs.length; i++) { - if(sm2.soundIDs[i] === sID) { - sm2.soundIDs.splice(i, 1); - break; - } - } - if(!_bFromSound) { - // ignore if being called from SMSound instance - oS.destruct(true); - } - oS = null; - delete sm2.sounds[sID]; - return true; - }; - /** - * Calls the load() method of a SMSound object by ID. - * - * @param {string} sID The ID of the sound - * @param {object} oOptions Optional: Sound options - */ - this.load = function(sID, oOptions) { - if(!idCheck(sID)) { - return false; - } - return sm2.sounds[sID].load(oOptions); - }; - /** - * Calls the unload() method of a SMSound object by ID. - * - * @param {string} sID The ID of the sound - */ - this.unload = function(sID) { - if(!idCheck(sID)) { - return false; - } - return sm2.sounds[sID].unload(); - }; - /** - * Calls the onPosition() method of a SMSound object by ID. - * - * @param {string} sID The ID of the sound - * @param {number} nPosition The position to watch for - * @param {function} oMethod The relevant callback to fire - * @param {object} oScope Optional: The scope to apply the callback to - * @return {SMSound} The SMSound object - */ - this.onPosition = function(sID, nPosition, oMethod, oScope) { - if(!idCheck(sID)) { - return false; - } - return sm2.sounds[sID].onposition(nPosition, oMethod, oScope); - }; - // legacy/backwards-compability: lower-case method name - this.onposition = this.onPosition; - /** - * Calls the clearOnPosition() method of a SMSound object by ID. - * - * @param {string} sID The ID of the sound - * @param {number} nPosition The position to watch for - * @param {function} oMethod Optional: The relevant callback to fire - * @return {SMSound} The SMSound object - */ - this.clearOnPosition = function(sID, nPosition, oMethod) { - if(!idCheck(sID)) { - return false; - } - return sm2.sounds[sID].clearOnPosition(nPosition, oMethod); - }; - /** - * Calls the play() method of a SMSound object by ID. - * - * @param {string} sID The ID of the sound - * @param {object} oOptions Optional: Sound options - * @return {SMSound} The SMSound object - */ - this.play = function(sID, oOptions) { - var result = null, - // legacy function-overloading use case: play('mySound', '/path/to/some.mp3'); - overloaded = (oOptions && !(oOptions instanceof Object)); - if(!didInit || !sm2.ok()) { - complain(sm + '.play(): ' + str(!didInit ? 'notReady' : 'notOK')); - return false; - } - if(!idCheck(sID, overloaded)) { - if(!overloaded) { - // no sound found for the given ID. Bail. - return false; - } - if(overloaded) { - oOptions = { - url: oOptions - }; - } - if(oOptions && oOptions.url) { - // overloading use case, create+play: .play('someID', {url:'/path/to.mp3'}); - sm2._wD(sm + '.play(): Attempting to create "' + sID + '"', 1); - oOptions.id = sID; - result = sm2.createSound(oOptions).play(); - } - } else if(overloaded) { - // existing sound object case - oOptions = { - url: oOptions - }; - } - if(result === null) { - // default case - result = sm2.sounds[sID].play(oOptions); - } - return result; - }; - this.start = this.play; // just for convenience - /** - * Calls the setPosition() method of a SMSound object by ID. - * - * @param {string} sID The ID of the sound - * @param {number} nMsecOffset Position (milliseconds) - * @return {SMSound} The SMSound object - */ - this.setPosition = function(sID, nMsecOffset) { - if(!idCheck(sID)) { - return false; - } - return sm2.sounds[sID].setPosition(nMsecOffset); - }; - /** - * Calls the stop() method of a SMSound object by ID. - * - * @param {string} sID The ID of the sound - * @return {SMSound} The SMSound object - */ - this.stop = function(sID) { - if(!idCheck(sID)) { - return false; - } - sm2._wD(sm + '.stop(' + sID + ')', 1); - return sm2.sounds[sID].stop(); - }; - /** - * Stops all currently-playing sounds. - */ - this.stopAll = function() { - var oSound; - sm2._wD(sm + '.stopAll()', 1); - for(oSound in sm2.sounds) { - if(sm2.sounds.hasOwnProperty(oSound)) { - // apply only to sound objects - sm2.sounds[oSound].stop(); - } - } - }; - /** - * Calls the pause() method of a SMSound object by ID. - * - * @param {string} sID The ID of the sound - * @return {SMSound} The SMSound object - */ - this.pause = function(sID) { - if(!idCheck(sID)) { - return false; - } - return sm2.sounds[sID].pause(); - }; - /** - * Pauses all currently-playing sounds. - */ - this.pauseAll = function() { - var i; - for(i = sm2.soundIDs.length - 1; i >= 0; i--) { - sm2.sounds[sm2.soundIDs[i]].pause(); - } - }; - /** - * Calls the resume() method of a SMSound object by ID. - * - * @param {string} sID The ID of the sound - * @return {SMSound} The SMSound object - */ - this.resume = function(sID) { - if(!idCheck(sID)) { - return false; - } - return sm2.sounds[sID].resume(); - }; - /** - * Resumes all currently-paused sounds. - */ - this.resumeAll = function() { - var i; - for(i = sm2.soundIDs.length - 1; i >= 0; i--) { - sm2.sounds[sm2.soundIDs[i]].resume(); - } - }; - /** - * Calls the togglePause() method of a SMSound object by ID. - * - * @param {string} sID The ID of the sound - * @return {SMSound} The SMSound object - */ - this.togglePause = function(sID) { - if(!idCheck(sID)) { - return false; - } - return sm2.sounds[sID].togglePause(); - }; - /** - * Calls the setPan() method of a SMSound object by ID. - * - * @param {string} sID The ID of the sound - * @param {number} nPan The pan value (-100 to 100) - * @return {SMSound} The SMSound object - */ - this.setPan = function(sID, nPan) { - if(!idCheck(sID)) { - return false; - } - return sm2.sounds[sID].setPan(nPan); - }; - /** - * Calls the setVolume() method of a SMSound object by ID. - * - * @param {string} sID The ID of the sound - * @param {number} nVol The volume value (0 to 100) - * @return {SMSound} The SMSound object - */ - this.setVolume = function(sID, nVol) { - if(!idCheck(sID)) { - return false; - } - return sm2.sounds[sID].setVolume(nVol); - }; - /** - * Calls the mute() method of either a single SMSound object by ID, or all sound objects. - * - * @param {string} sID Optional: The ID of the sound (if omitted, all sounds will be used.) - */ - this.mute = function(sID) { - var i = 0; - if(sID instanceof String) { - sID = null; - } - if(!sID) { - sm2._wD(sm + '.mute(): Muting all sounds'); - for(i = sm2.soundIDs.length - 1; i >= 0; i--) { - sm2.sounds[sm2.soundIDs[i]].mute(); - } - sm2.muted = true; - } else { - if(!idCheck(sID)) { - return false; - } - sm2._wD(sm + '.mute(): Muting "' + sID + '"'); - return sm2.sounds[sID].mute(); - } - return true; - }; - /** - * Mutes all sounds. - */ - this.muteAll = function() { - sm2.mute(); - }; - /** - * Calls the unmute() method of either a single SMSound object by ID, or all sound objects. - * - * @param {string} sID Optional: The ID of the sound (if omitted, all sounds will be used.) - */ - this.unmute = function(sID) { - var i; - if(sID instanceof String) { - sID = null; - } - if(!sID) { - sm2._wD(sm + '.unmute(): Unmuting all sounds'); - for(i = sm2.soundIDs.length - 1; i >= 0; i--) { - sm2.sounds[sm2.soundIDs[i]].unmute(); - } - sm2.muted = false; - } else { - if(!idCheck(sID)) { - return false; - } - sm2._wD(sm + '.unmute(): Unmuting "' + sID + '"'); - return sm2.sounds[sID].unmute(); - } - return true; - }; - /** - * Unmutes all sounds. - */ - this.unmuteAll = function() { - sm2.unmute(); - }; - /** - * Calls the toggleMute() method of a SMSound object by ID. - * - * @param {string} sID The ID of the sound - * @return {SMSound} The SMSound object - */ - this.toggleMute = function(sID) { - if(!idCheck(sID)) { - return false; - } - return sm2.sounds[sID].toggleMute(); - }; - /** - * Retrieves the memory used by the flash plugin. - * - * @return {number} The amount of memory in use - */ - this.getMemoryUse = function() { - // flash-only - var ram = 0; - if(flash && fV !== 8) { - ram = parseInt(flash._getMemoryUse(), 10); - } - return ram; - }; - /** - * Undocumented: NOPs soundManager and all SMSound objects. - */ - this.disable = function(bNoDisable) { - // destroy all functions - var i; - if(bNoDisable === _undefined) { - bNoDisable = false; - } - if(disabled) { - return false; - } - disabled = true; - _wDS('shutdown', 1); - for(i = sm2.soundIDs.length - 1; i >= 0; i--) { - disableObject(sm2.sounds[sm2.soundIDs[i]]); - } - // fire "complete", despite fail - initComplete(bNoDisable); - event.remove(window, 'load', initUserOnload); - return true; - }; - /** - * Determines playability of a MIME type, eg. 'audio/mp3'. - */ - this.canPlayMIME = function(sMIME) { - var result; - if(sm2.hasHTML5) { - result = html5CanPlay({ - type: sMIME - }); - } - if(!result && needsFlash) { - // if flash 9, test netStream (movieStar) types as well. - result = (sMIME && sm2.ok() ? !! ((fV > 8 ? sMIME.match(netStreamMimeTypes) : null) || sMIME.match(sm2.mimePattern)) : null); // TODO: make less "weird" (per JSLint) - } - return result; - }; - /** - * Determines playability of a URL based on audio support. - * - * @param {string} sURL The URL to test - * @return {boolean} URL playability - */ - this.canPlayURL = function(sURL) { - var result; - if(sm2.hasHTML5) { - result = html5CanPlay({ - url: sURL - }); - } - if(!result && needsFlash) { - result = (sURL && sm2.ok() ? !! (sURL.match(sm2.filePattern)) : null); - } - return result; - }; - /** - * Determines playability of an HTML DOM <a> object (or similar object literal) based on audio support. - * - * @param {object} oLink an HTML DOM <a> object or object literal including href and/or type attributes - * @return {boolean} URL playability - */ - this.canPlayLink = function(oLink) { - if(oLink.type !== _undefined && oLink.type) { - if(sm2.canPlayMIME(oLink.type)) { - return true; - } - } - return sm2.canPlayURL(oLink.href); - }; - /** - * Retrieves a SMSound object by ID. - * - * @param {string} sID The ID of the sound - * @return {SMSound} The SMSound object - */ - this.getSoundById = function(sID, _suppressDebug) { - if(!sID) { - return null; - } - var result = sm2.sounds[sID]; - // - if(!result && !_suppressDebug) { - sm2._wD(sm + '.getSoundById(): Sound "' + sID + '" not found.', 2); - } - // - return result; - }; - /** - * Queues a callback for execution when SoundManager has successfully initialized. - * - * @param {function} oMethod The callback method to fire - * @param {object} oScope Optional: The scope to apply to the callback - */ - this.onready = function(oMethod, oScope) { - var sType = 'onready', - result = false; - if(typeof oMethod === 'function') { - // - if(didInit) { - sm2._wD(str('queue', sType)); - } - // - if(!oScope) { - oScope = window; - } - addOnEvent(sType, oMethod, oScope); - processOnEvents(); - result = true; - } else { - throw str('needFunction', sType); - } - return result; - }; - /** - * Queues a callback for execution when SoundManager has failed to initialize. - * - * @param {function} oMethod The callback method to fire - * @param {object} oScope Optional: The scope to apply to the callback - */ - this.ontimeout = function(oMethod, oScope) { - var sType = 'ontimeout', - result = false; - if(typeof oMethod === 'function') { - // - if(didInit) { - sm2._wD(str('queue', sType)); - } - // - if(!oScope) { - oScope = window; - } - addOnEvent(sType, oMethod, oScope); - processOnEvents({ - type: sType - }); - result = true; - } else { - throw str('needFunction', sType); - } - return result; - }; - /** - * Writes console.log()-style debug output to a console or in-browser element. - * Applies when debugMode = true - * - * @param {string} sText The console message - * @param {object} nType Optional log level (number), or object. Number case: Log type/style where 0 = 'info', 1 = 'warn', 2 = 'error'. Object case: Object to be dumped. - */ - this._writeDebug = function(sText, sTypeOrObject) { - // pseudo-private console.log()-style output - // - var sDID = 'soundmanager-debug', - o, oItem; - if(!sm2.debugMode) { - return false; - } - if(hasConsole && sm2.useConsole) { - if(sTypeOrObject && typeof sTypeOrObject === 'object') { - // object passed; dump to console. - console.log(sText, sTypeOrObject); - } else if(debugLevels[sTypeOrObject] !== _undefined) { - console[debugLevels[sTypeOrObject]](sText); - } else { - console.log(sText); - } - if(sm2.consoleOnly) { - return true; - } - } - o = id(sDID); - if(!o) { - return false; - } - oItem = doc.createElement('div'); - if(++wdCount % 2 === 0) { - oItem.className = 'sm2-alt'; - } - if(sTypeOrObject === _undefined) { - sTypeOrObject = 0; - } else { - sTypeOrObject = parseInt(sTypeOrObject, 10); - } - oItem.appendChild(doc.createTextNode(sText)); - if(sTypeOrObject) { - if(sTypeOrObject >= 2) { - oItem.style.fontWeight = 'bold'; - } - if(sTypeOrObject === 3) { - oItem.style.color = '#ff3333'; - } - } - // top-to-bottom - // o.appendChild(oItem); - // bottom-to-top - o.insertBefore(oItem, o.firstChild); - o = null; - // - return true; - }; // - // last-resort debugging option - if(wl.indexOf('sm2-debug=alert') !== -1) { - this._writeDebug = function(sText) { - window.alert(sText); - }; + if (!sm2.setupOptions.useHTML5Audio || sm2.setupOptions.preferFlash) { + // notify that defaults are being changed. + sm2._wD(strings.mobileUA); } // - // alias - this._wD = this._writeDebug; - /** - * Provides debug / state information on all SMSound objects. - */ - this._debug = function() { - // - var i, j; - _wDS('currentObj', 1); - for(i = 0, j = sm2.soundIDs.length; i < j; i++) { - sm2.sounds[sm2.soundIDs[i]]._debug(); - } - // - }; - /** - * Restarts and re-initializes the SoundManager instance. - * - * @param {boolean} resetEvents Optional: When true, removes all registered onready and ontimeout event callbacks. - * @param {boolean} excludeInit Options: When true, does not call beginDelayedInit() (which would restart SM2). - * @return {object} soundManager The soundManager instance. - */ - this.reboot = function(resetEvents, excludeInit) { - // reset some (or all) state, and re-init unless otherwise specified. - // - if(sm2.soundIDs.length) { - sm2._wD('Destroying ' + sm2.soundIDs.length + ' SMSound object' + (sm2.soundIDs.length !== 1 ? 's' : '') + '...'); - } - // - var i, j, k; - for(i = sm2.soundIDs.length - 1; i >= 0; i--) { - sm2.sounds[sm2.soundIDs[i]].destruct(); - } - // trash ze flash (remove from the DOM) - if(flash) { - try { - if(isIE) { - oRemovedHTML = flash.innerHTML; - } - oRemoved = flash.parentNode.removeChild(flash); - } catch(e) { - // Remove failed? May be due to flash blockers silently removing the SWF object/embed node from the DOM. Warn and continue. - _wDS('badRemove', 2); - } - } - // actually, force recreate of movie. - oRemovedHTML = oRemoved = needsFlash = flash = null; - sm2.enabled = didDCLoaded = didInit = waitingForEI = initPending = didAppend = appendSuccess = disabled = useGlobalHTML5Audio = sm2.swfLoaded = false; - sm2.soundIDs = []; - sm2.sounds = {}; - idCounter = 0; - if(!resetEvents) { - // reset callbacks for onready, ontimeout etc. so that they will fire again on re-init - for(i in on_queue) { - if(on_queue.hasOwnProperty(i)) { - for(j = 0, k = on_queue[i].length; j < k; j++) { - on_queue[i][j].fired = false; - } - } - } - } else { - // remove all callbacks entirely - on_queue = []; - } - // - if(!excludeInit) { - sm2._wD(sm + ': Rebooting...'); - } - // - // reset HTML5 and flash canPlay test results - sm2.html5 = { - 'usingFlash': null - }; - sm2.flash = {}; - // reset device-specific HTML/flash mode switches - sm2.html5Only = false; - sm2.ignoreFlash = false; - window.setTimeout(function() { - preInit(); - // by default, re-init - if(!excludeInit) { - sm2.beginDelayedInit(); - } - }, 20); - return sm2; - }; - this.reset = function() { - /** - * Shuts down and restores the SoundManager instance to its original loaded state, without an explicit reboot. All onready/ontimeout handlers are removed. - * After this call, SM2 may be re-initialized via soundManager.beginDelayedInit(). - * @return {object} soundManager The soundManager instance. - */ - _wDS('reset'); - return sm2.reboot(true, true); - }; - /** - * Undocumented: Determines the SM2 flash movie's load progress. - * - * @return {number or null} Percent loaded, or if invalid/unsupported, null. - */ - this.getMoviePercent = function() { - /** - * Interesting syntax notes... - * Flash/ExternalInterface (ActiveX/NPAPI) bridge methods are not typeof "function" nor instanceof Function, but are still valid. - * Additionally, JSLint dislikes ('PercentLoaded' in flash)-style syntax and recommends hasOwnProperty(), which does not work in this case. - * Furthermore, using (flash && flash.PercentLoaded) causes IE to throw "object doesn't support this property or method". - * Thus, 'in' syntax must be used. - */ - return(flash && 'PercentLoaded' in flash ? flash.PercentLoaded() : null); // Yes, JSLint. See nearby comment in source for explanation. - }; - /** - * Additional helper for manually invoking SM2's init process after DOM Ready / window.onload(). - */ - this.beginDelayedInit = function() { - windowLoaded = true; - domContentLoaded(); - setTimeout(function() { - if(initPending) { - return false; - } - createMovie(); - initMovie(); - initPending = true; - return true; - }, 20); - delayWaitForEI(); - }; - /** - * Destroys the SoundManager instance and all SMSound instances. - */ - this.destruct = function() { - sm2._wD(sm + '.destruct()'); - sm2.disable(true); + + sm2.setupOptions.useHTML5Audio = true; + sm2.setupOptions.preferFlash = false; + + if (is_iDevice) { + + // no flash here. + sm2.ignoreFlash = true; + + } else if ((isAndroid && !ua.match(/android\s2\.3/i)) || !isAndroid) { + + /** + * Android devices tend to work better with a single audio instance, specifically for chained playback of sounds in sequence. + * Common use case: exiting sound onfinish() -> createSound() -> play() + * Presuming similar restrictions for other mobile, non-Android, non-iOS devices. + */ + + // + sm2._wD(strings.globalHTML5); + // + + useGlobalHTML5Audio = true; + + } + + } + + } + + // special case 1: "Late setup". SM2 loaded normally, but user didn't assign flash URL eg., setup({url:...}) before SM2 init. Treat as delayed init. + + if (options) { + + if (noURL && didDCLoaded && options.url !== _undefined) { + sm2.beginDelayedInit(); + } + + // special case 2: If lazy-loading SM2 (DOMContentLoaded has already happened) and user calls setup() with url: parameter, try to init ASAP. + + if (!didDCLoaded && options.url !== _undefined && doc.readyState === 'complete') { + setTimeout(domContentLoaded, 1); + } + + } + + didSetup = true; + + return sm2; + + }; + + this.ok = function() { + + return (needsFlash ? (didInit && !disabled) : (sm2.useHTML5Audio && sm2.hasHTML5)); + + }; + + this.supported = this.ok; // legacy + + this.getMovie = function(movie_id) { + + // safety net: some old browsers differ on SWF references, possibly related to ExternalInterface / flash version + return id(movie_id) || doc[movie_id] || window[movie_id]; + + }; + + /** + * Creates a SMSound sound object instance. Can also be overloaded, e.g., createSound('mySound', '/some.mp3'); + * + * @param {object} oOptions Sound options (at minimum, url parameter is required.) + * @return {object} SMSound The new SMSound object. + */ + + this.createSound = function(oOptions, _url) { + + var cs, cs_string, options, oSound = null; + + // + cs = sm + '.createSound(): '; + cs_string = cs + str(!didInit ? 'notReady' : 'notOK'); + // + + if (!didInit || !sm2.ok()) { + complain(cs_string); + return false; + } + + if (_url !== _undefined) { + // function overloading in JS! :) ... assume simple createSound(id, url) use case. + oOptions = { + id: oOptions, + url: _url + }; + } + + // inherit from defaultOptions + options = mixin(oOptions); + + options.url = parseURL(options.url); + + // generate an id, if needed. + if (options.id === _undefined) { + options.id = sm2.setupOptions.idPrefix + (idCounter++); + } + + // + if (options.id.toString().charAt(0).match(/^[0-9]$/)) { + sm2._wD(cs + str('badID', options.id), 2); + } + + sm2._wD(cs + options.id + (options.url ? ' (' + options.url + ')' : ''), 1); + // + + if (idCheck(options.id, true)) { + sm2._wD(cs + options.id + ' exists', 1); + return sm2.sounds[options.id]; + } + + function make() { + + options = loopFix(options); + sm2.sounds[options.id] = new SMSound(options); + sm2.soundIDs.push(options.id); + return sm2.sounds[options.id]; + + } + + if (html5OK(options)) { + + oSound = make(); + // + if (!sm2.html5Only) { + sm2._wD(options.id + ': Using HTML5'); + } + // + oSound._setup_html5(options); + + } else { + + if (sm2.html5Only) { + sm2._wD(options.id + ': No HTML5 support for this sound, and no Flash. Exiting.'); + return make(); + } + + // TODO: Move HTML5/flash checks into generic URL parsing/handling function. + + if (sm2.html5.usingFlash && options.url && options.url.match(/data:/i)) { + // data: URIs not supported by Flash, either. + sm2._wD(options.id + ': data: URIs not supported via Flash. Exiting.'); + return make(); + } + + if (fV > 8) { + if (options.isMovieStar === null) { + // attempt to detect MPEG-4 formats + options.isMovieStar = !!(options.serverURL || (options.type ? options.type.match(netStreamMimeTypes) : false) || (options.url && options.url.match(netStreamPattern))); + } + // + if (options.isMovieStar) { + sm2._wD(cs + 'using MovieStar handling'); + if (options.loops > 1) { + _wDS('noNSLoop'); + } + } + // + } + + options = policyFix(options, cs); + oSound = make(); + + if (fV === 8) { + flash._createSound(options.id, options.loops || 1, options.usePolicyFile); + } else { + flash._createSound(options.id, options.url, options.usePeakData, options.useWaveformData, options.useEQData, options.isMovieStar, (options.isMovieStar ? options.bufferTime : false), options.loops || 1, options.serverURL, options.duration || null, options.autoPlay, true, options.autoLoad, options.usePolicyFile); + if (!options.serverURL) { + // We are connected immediately + oSound.connected = true; + if (options.onconnect) { + options.onconnect.apply(oSound); + } + } + } + + if (!options.serverURL && (options.autoLoad || options.autoPlay)) { + // call load for non-rtmp streams + oSound.load(options); + } + + } + + // rtmp will play in onconnect + if (!options.serverURL && options.autoPlay) { + oSound.play(); + } + + return oSound; + + }; + + /** + * Destroys a SMSound sound object instance. + * + * @param {string} sID The ID of the sound to destroy + */ + + this.destroySound = function(sID, _bFromSound) { + + // explicitly destroy a sound before normal page unload, etc. + + if (!idCheck(sID)) return false; + + var oS = sm2.sounds[sID], i; + + oS.stop(); + + // Disable all callbacks after stop(), when the sound is being destroyed + oS._iO = {}; + + oS.unload(); + + for (i = 0; i < sm2.soundIDs.length; i++) { + if (sm2.soundIDs[i] === sID) { + sm2.soundIDs.splice(i, 1); + break; + } + } + + if (!_bFromSound) { + // ignore if being called from SMSound instance + oS.destruct(true); + } + + oS = null; + delete sm2.sounds[sID]; + + return true; + + }; + + /** + * Calls the load() method of a SMSound object by ID. + * + * @param {string} sID The ID of the sound + * @param {object} oOptions Optional: Sound options + */ + + this.load = function(sID, oOptions) { + + if (!idCheck(sID)) return false; + + return sm2.sounds[sID].load(oOptions); + + }; + + /** + * Calls the unload() method of a SMSound object by ID. + * + * @param {string} sID The ID of the sound + */ + + this.unload = function(sID) { + + if (!idCheck(sID)) return false; + + return sm2.sounds[sID].unload(); + + }; + + /** + * Calls the onPosition() method of a SMSound object by ID. + * + * @param {string} sID The ID of the sound + * @param {number} nPosition The position to watch for + * @param {function} oMethod The relevant callback to fire + * @param {object} oScope Optional: The scope to apply the callback to + * @return {SMSound} The SMSound object + */ + + this.onPosition = function(sID, nPosition, oMethod, oScope) { + + if (!idCheck(sID)) return false; + + return sm2.sounds[sID].onposition(nPosition, oMethod, oScope); + + }; + + // legacy/backwards-compability: lower-case method name + this.onposition = this.onPosition; + + /** + * Calls the clearOnPosition() method of a SMSound object by ID. + * + * @param {string} sID The ID of the sound + * @param {number} nPosition The position to watch for + * @param {function} oMethod Optional: The relevant callback to fire + * @return {SMSound} The SMSound object + */ + + this.clearOnPosition = function(sID, nPosition, oMethod) { + + if (!idCheck(sID)) return false; + + return sm2.sounds[sID].clearOnPosition(nPosition, oMethod); + + }; + + /** + * Calls the play() method of a SMSound object by ID. + * + * @param {string} sID The ID of the sound + * @param {object} oOptions Optional: Sound options + * @return {SMSound} The SMSound object + */ + + this.play = function(sID, oOptions) { + + var result = null, + // legacy function-overloading use case: play('mySound', '/path/to/some.mp3'); + overloaded = (oOptions && !(oOptions instanceof Object)); + + if (!didInit || !sm2.ok()) { + complain(sm + '.play(): ' + str(!didInit ? 'notReady' : 'notOK')); + return false; + } + + if (!idCheck(sID, overloaded)) { + + // no sound found for the given ID. Bail. + if (!overloaded) return false; + + if (overloaded) { + oOptions = { + url: oOptions }; - /** - * SMSound() (sound object) constructor - * ------------------------------------ - * - * @param {object} oOptions Sound options (id and url are required attributes) - * @return {SMSound} The new SMSound object - */ - SMSound = function(oOptions) { - var s = this, - resetProperties, add_html5_events, remove_html5_events, stop_html5_timer, start_html5_timer, attachOnPosition, onplay_called = false, - onPositionItems = [], - onPositionFired = 0, - detachOnPosition, applyFromTo, lastURL = null, - lastHTML5State, urlOmitted; - lastHTML5State = { - // tracks duration + position (time) - duration: null, - time: null - }; - this.id = oOptions.id; - // legacy - this.sID = this.id; - this.url = oOptions.url; - this.options = mixin(oOptions); - // per-play-instance-specific options - this.instanceOptions = this.options; - // short alias - this._iO = this.instanceOptions; - // assign property defaults - this.pan = this.options.pan; - this.volume = this.options.volume; - // whether or not this object is using HTML5 - this.isHTML5 = false; - // internal HTML5 Audio() object reference - this._a = null; - // for flash 8 special-case createSound() without url, followed by load/play with url case - urlOmitted = (this.url ? false : true); - /** - * SMSound() public methods - * ------------------------ - */ - this.id3 = {}; - /** - * Writes SMSound object parameters to debug console - */ - this._debug = function() { - // - sm2._wD(s.id + ': Merged options:', s.options); - // - }; - /** - * Begins loading a sound per its *url*. - * - * @param {object} oOptions Optional: Sound options - * @return {SMSound} The SMSound object - */ - this.load = function(oOptions) { - var oSound = null, - instanceOptions; - if(oOptions !== _undefined) { - s._iO = mixin(oOptions, s.options); - } else { - oOptions = s.options; - s._iO = oOptions; - if(lastURL && lastURL !== s.url) { - _wDS('manURL'); - s._iO.url = s.url; - s.url = null; - } - } - if(!s._iO.url) { - s._iO.url = s.url; - } - s._iO.url = parseURL(s._iO.url); - // ensure we're in sync - s.instanceOptions = s._iO; - // local shortcut - instanceOptions = s._iO; - sm2._wD(s.id + ': load (' + instanceOptions.url + ')'); - if(!instanceOptions.url && !s.url) { - sm2._wD(s.id + ': load(): url is unassigned. Exiting.', 2); - return s; - } - // - if(!s.isHTML5 && fV === 8 && !s.url && !instanceOptions.autoPlay) { - // flash 8 load() -> play() won't work before onload has fired. - sm2._wD(s.id + ': Flash 8 load() limitation: Wait for onload() before calling play().', 1); - } - // - if(instanceOptions.url === s.url && s.readyState !== 0 && s.readyState !== 2) { - _wDS('onURL', 1); - // if loaded and an onload() exists, fire immediately. - if(s.readyState === 3 && instanceOptions.onload) { - // assume success based on truthy duration. - wrapCallback(s, function() { - instanceOptions.onload.apply(s, [( !! s.duration)]); - }); - } - return s; - } - // reset a few state properties - s.loaded = false; - s.readyState = 1; - s.playState = 0; - s.id3 = {}; - // TODO: If switching from HTML5 -> flash (or vice versa), stop currently-playing audio. - if(html5OK(instanceOptions)) { - oSound = s._setup_html5(instanceOptions); - if(!oSound._called_load) { - s._html5_canplay = false; - // TODO: review called_load / html5_canplay logic - // if url provided directly to load(), assign it here. - if(s.url !== instanceOptions.url) { - sm2._wD(_wDS('manURL') + ': ' + instanceOptions.url); - s._a.src = instanceOptions.url; - // TODO: review / re-apply all relevant options (volume, loop, onposition etc.) - // reset position for new URL - s.setPosition(0); - } - // given explicit load call, try to preload. - // early HTML5 implementation (non-standard) - s._a.autobuffer = 'auto'; - // standard property, values: none / metadata / auto - // reference: http://msdn.microsoft.com/en-us/library/ie/ff974759%28v=vs.85%29.aspx - s._a.preload = 'auto'; - s._a._called_load = true; - } else { - sm2._wD(s.id + ': Ignoring request to load again'); - } - } else { - if(sm2.html5Only) { - sm2._wD(s.id + ': No flash support. Exiting.'); - return s; - } - if(s._iO.url && s._iO.url.match(/data\:/i)) { - // data: URIs not supported by Flash, either. - sm2._wD(s.id + ': data: URIs not supported via Flash. Exiting.'); - return s; - } - try { - s.isHTML5 = false; - s._iO = policyFix(loopFix(instanceOptions)); - // if we have "position", disable auto-play as we'll be seeking to that position at onload(). - if(s._iO.autoPlay && (s._iO.position || s._iO.from)) { - sm2._wD(s.id + ': Disabling autoPlay because of non-zero offset case'); - s._iO.autoPlay = false; - } - // re-assign local shortcut - instanceOptions = s._iO; - if(fV === 8) { - flash._load(s.id, instanceOptions.url, instanceOptions.stream, instanceOptions.autoPlay, instanceOptions.usePolicyFile); - } else { - flash._load(s.id, instanceOptions.url, !! (instanceOptions.stream), !! (instanceOptions.autoPlay), instanceOptions.loops || 1, !! (instanceOptions.autoLoad), instanceOptions.usePolicyFile); - } - } catch(e) { - _wDS('smError', 2); - debugTS('onload', false); - catchError({ - type: 'SMSOUND_LOAD_JS_EXCEPTION', - fatal: true - }); - } - } - // after all of this, ensure sound url is up to date. - s.url = instanceOptions.url; - return s; - }; - /** - * Unloads a sound, canceling any open HTTP requests. - * - * @return {SMSound} The SMSound object - */ - this.unload = function() { - // Flash 8/AS2 can't "close" a stream - fake it by loading an empty URL - // Flash 9/AS3: Close stream, preventing further load - // HTML5: Most UAs will use empty URL - if(s.readyState !== 0) { - sm2._wD(s.id + ': unload()'); - if(!s.isHTML5) { - if(fV === 8) { - flash._unload(s.id, emptyURL); - } else { - flash._unload(s.id); - } - } else { - stop_html5_timer(); - if(s._a) { - s._a.pause(); - // update empty URL, too - lastURL = html5Unload(s._a); - } - } - // reset load/status flags - resetProperties(); - } - return s; - }; - /** - * Unloads and destroys a sound. - */ - this.destruct = function(_bFromSM) { - sm2._wD(s.id + ': Destruct'); - if(!s.isHTML5) { - // kill sound within Flash - // Disable the onfailure handler - s._iO.onfailure = null; - flash._destroySound(s.id); - } else { - stop_html5_timer(); - if(s._a) { - s._a.pause(); - html5Unload(s._a); - if(!useGlobalHTML5Audio) { - remove_html5_events(); - } - // break obvious circular reference - s._a._s = null; - s._a = null; - } - } - if(!_bFromSM) { - // ensure deletion from controller - sm2.destroySound(s.id, true); - } - }; - /** - * Begins playing a sound. - * - * @param {object} oOptions Optional: Sound options - * @return {SMSound} The SMSound object - */ - this.play = function(oOptions, _updatePlayState) { - var fN, allowMulti, a, onready, - audioClone, onended, oncanplay, - startOK = true, - exit = null; - // - fN = s.id + ': play(): '; - // - // default to true - _updatePlayState = (_updatePlayState === _undefined ? true : _updatePlayState); - if(!oOptions) { - oOptions = {}; - } - // first, use local URL (if specified) - if(s.url) { - s._iO.url = s.url; - } - // mix in any options defined at createSound() - s._iO = mixin(s._iO, s.options); - // mix in any options specific to this method - s._iO = mixin(oOptions, s._iO); - s._iO.url = parseURL(s._iO.url); - s.instanceOptions = s._iO; - // RTMP-only - if(!s.isHTML5 && s._iO.serverURL && !s.connected) { - if(!s.getAutoPlay()) { - sm2._wD(fN + ' Netstream not connected yet - setting autoPlay'); - s.setAutoPlay(true); - } - // play will be called in onconnect() - return s; - } - if(html5OK(s._iO)) { - s._setup_html5(s._iO); - start_html5_timer(); - } - if(s.playState === 1 && !s.paused) { - allowMulti = s._iO.multiShot; - if(!allowMulti) { - sm2._wD(fN + 'Already playing (one-shot)', 1); - if(s.isHTML5) { - // go back to original position. - s.setPosition(s._iO.position); - } - exit = s; - } else { - sm2._wD(fN + 'Already playing (multi-shot)', 1); - } - } - if(exit !== null) { - return exit; - } - // edge case: play() with explicit URL parameter - if(oOptions.url && oOptions.url !== s.url) { - // special case for createSound() followed by load() / play() with url; avoid double-load case. - if(!s.readyState && !s.isHTML5 && fV === 8 && urlOmitted) { - urlOmitted = false; - } else { - // load using merged options - s.load(s._iO); - } - } - if(!s.loaded) { - if(s.readyState === 0) { - sm2._wD(fN + 'Attempting to load'); - // try to get this sound playing ASAP - if(!s.isHTML5 && !sm2.html5Only) { - // flash: assign directly because setAutoPlay() increments the instanceCount - s._iO.autoPlay = true; - s.load(s._iO); - } else if(s.isHTML5) { - // iOS needs this when recycling sounds, loading a new URL on an existing object. - s.load(s._iO); - } else { - sm2._wD(fN + 'Unsupported type. Exiting.'); - exit = s; - } - // HTML5 hack - re-set instanceOptions? - s.instanceOptions = s._iO; - } else if(s.readyState === 2) { - sm2._wD(fN + 'Could not load - exiting', 2); - exit = s; - } else { - sm2._wD(fN + 'Loading - attempting to play...'); - } - } else { - // "play()" - sm2._wD(fN.substr(0, fN.lastIndexOf(':'))); - } - if(exit !== null) { - return exit; - } - if(!s.isHTML5 && fV === 9 && s.position > 0 && s.position === s.duration) { - // flash 9 needs a position reset if play() is called while at the end of a sound. - sm2._wD(fN + 'Sound at end, resetting to position:0'); - oOptions.position = 0; - } - /** - * Streams will pause when their buffer is full if they are being loaded. - * In this case paused is true, but the song hasn't started playing yet. - * If we just call resume() the onplay() callback will never be called. - * So only call resume() if the position is > 0. - * Another reason is because options like volume won't have been applied yet. - * For normal sounds, just resume. - */ - if(s.paused && s.position >= 0 && (!s._iO.serverURL || s.position > 0)) { - // https://gist.github.com/37b17df75cc4d7a90bf6 - sm2._wD(fN + 'Resuming from paused state', 1); - s.resume(); - } else { - s._iO = mixin(oOptions, s._iO); - /** - * Preload in the event of play() with position under Flash, - * or from/to parameters and non-RTMP case - */ - if(((!s.isHTML5 && s._iO.position !== null && s._iO.position > 0) || (s._iO.from !== null && s._iO.from > 0) || s._iO.to !== null) && s.instanceCount === 0 && s.playState === 0 && !s._iO.serverURL) { - onready = function() { - // sound "canplay" or onload() - // re-apply position/from/to to instance options, and start playback - s._iO = mixin(oOptions, s._iO); - s.play(s._iO); - }; - // HTML5 needs to at least have "canplay" fired before seeking. - if(s.isHTML5 && !s._html5_canplay) { - // this hasn't been loaded yet. load it first, and then do this again. - sm2._wD(fN + 'Beginning load for non-zero offset case'); - s.load({ - // note: custom HTML5-only event added for from/to implementation. - _oncanplay: onready - }); - exit = false; - } else if(!s.isHTML5 && !s.loaded && (!s.readyState || s.readyState !== 2)) { - // to be safe, preload the whole thing in Flash. - sm2._wD(fN + 'Preloading for non-zero offset case'); - s.load({ - onload: onready - }); - exit = false; - } - if(exit !== null) { - return exit; - } - // otherwise, we're ready to go. re-apply local options, and continue - s._iO = applyFromTo(); - } - // sm2._wD(fN + 'Starting to play'); - // increment instance counter, where enabled + supported - if(!s.instanceCount || s._iO.multiShotEvents || (s.isHTML5 && s._iO.multiShot && !useGlobalHTML5Audio) || (!s.isHTML5 && fV > 8 && !s.getAutoPlay())) { - s.instanceCount++; - } - // if first play and onposition parameters exist, apply them now - if(s._iO.onposition && s.playState === 0) { - attachOnPosition(s); - } - s.playState = 1; - s.paused = false; - s.position = (s._iO.position !== _undefined && !isNaN(s._iO.position) ? s._iO.position : 0); - if(!s.isHTML5) { - s._iO = policyFix(loopFix(s._iO)); - } - if(s._iO.onplay && _updatePlayState) { - s._iO.onplay.apply(s); - onplay_called = true; - } - s.setVolume(s._iO.volume, true); - s.setPan(s._iO.pan, true); - if(!s.isHTML5) { - startOK = flash._start(s.id, s._iO.loops || 1, (fV === 9 ? s.position : s.position / msecScale), s._iO.multiShot || false); - if(fV === 9 && !startOK) { - // edge case: no sound hardware, or 32-channel flash ceiling hit. - // applies only to Flash 9, non-NetStream/MovieStar sounds. - // http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/Sound.html#play%28%29 - sm2._wD(fN + 'No sound hardware, or 32-sound ceiling hit', 2); - if(s._iO.onplayerror) { - s._iO.onplayerror.apply(s); - } - } - } else { - if(s.instanceCount < 2) { - // HTML5 single-instance case - start_html5_timer(); - a = s._setup_html5(); - s.setPosition(s._iO.position); - a.play(); - } else { - // HTML5 multi-shot case - sm2._wD(s.id + ': Cloning Audio() for instance #' + s.instanceCount + '...'); - audioClone = new Audio(s._iO.url); - onended = function() { - event.remove(audioClone, 'ended', onended); - s._onfinish(s); - // cleanup - html5Unload(audioClone); - audioClone = null; - }; - oncanplay = function() { - event.remove(audioClone, 'canplay', oncanplay); - try { - audioClone.currentTime = s._iO.position / msecScale; - } catch(err) { - complain(s.id + ': multiShot play() failed to apply position of ' + (s._iO.position / msecScale)); - } - audioClone.play(); - }; - event.add(audioClone, 'ended', onended); - // apply volume to clones, too - if(s._iO.volume !== undefined) { - audioClone.volume = Math.max(0, Math.min(1, s._iO.volume / 100)); - } - // playing multiple muted sounds? if you do this, you're weird ;) - but let's cover it. - if(s.muted) { - audioClone.muted = true; - } - if(s._iO.position) { - // HTML5 audio can't seek before onplay() event has fired. - // wait for canplay, then seek to position and start playback. - event.add(audioClone, 'canplay', oncanplay); - } else { - // begin playback at currentTime: 0 - audioClone.play(); - } - } - } - } - return s; - }; - // just for convenience - this.start = this.play; - /** - * Stops playing a sound (and optionally, all sounds) - * - * @param {boolean} bAll Optional: Whether to stop all sounds - * @return {SMSound} The SMSound object - */ - this.stop = function(bAll) { - var instanceOptions = s._iO, - originalPosition; - if(s.playState === 1) { - sm2._wD(s.id + ': stop()'); - s._onbufferchange(0); - s._resetOnPosition(0); - s.paused = false; - if(!s.isHTML5) { - s.playState = 0; - } - // remove onPosition listeners, if any - detachOnPosition(); - // and "to" position, if set - if(instanceOptions.to) { - s.clearOnPosition(instanceOptions.to); - } - if(!s.isHTML5) { - flash._stop(s.id, bAll); - // hack for netStream: just unload - if(instanceOptions.serverURL) { - s.unload(); - } - } else { - if(s._a) { - originalPosition = s.position; - // act like Flash, though - s.setPosition(0); - // hack: reflect old position for onstop() (also like Flash) - s.position = originalPosition; - // html5 has no stop() - // NOTE: pausing means iOS requires interaction to resume. - s._a.pause(); - s.playState = 0; - // and update UI - s._onTimer(); - stop_html5_timer(); - } - } - s.instanceCount = 0; - s._iO = {}; - if(instanceOptions.onstop) { - instanceOptions.onstop.apply(s); - } - } - return s; - }; - /** - * Undocumented/internal: Sets autoPlay for RTMP. - * - * @param {boolean} autoPlay state - */ - this.setAutoPlay = function(autoPlay) { - sm2._wD(s.id + ': Autoplay turned ' + (autoPlay ? 'on' : 'off')); - s._iO.autoPlay = autoPlay; - if(!s.isHTML5) { - flash._setAutoPlay(s.id, autoPlay); - if(autoPlay) { - // only increment the instanceCount if the sound isn't loaded (TODO: verify RTMP) - if(!s.instanceCount && s.readyState === 1) { - s.instanceCount++; - sm2._wD(s.id + ': Incremented instance count to ' + s.instanceCount); - } - } - } - }; - /** - * Undocumented/internal: Returns the autoPlay boolean. - * - * @return {boolean} The current autoPlay value - */ - this.getAutoPlay = function() { - return s._iO.autoPlay; - }; - /** - * Sets the position of a sound. - * - * @param {number} nMsecOffset Position (milliseconds) - * @return {SMSound} The SMSound object - */ - this.setPosition = function(nMsecOffset) { - if(nMsecOffset === _undefined) { - nMsecOffset = 0; - } - var position, position1K, - // Use the duration from the instance options, if we don't have a track duration yet. - // position >= 0 and <= current available (loaded) duration - offset = (s.isHTML5 ? Math.max(nMsecOffset, 0) : Math.min(s.duration || s._iO.duration, Math.max(nMsecOffset, 0))); - s.position = offset; - position1K = s.position / msecScale; - s._resetOnPosition(s.position); - s._iO.position = offset; - if(!s.isHTML5) { - position = (fV === 9 ? s.position : position1K); - if(s.readyState && s.readyState !== 2) { - // if paused or not playing, will not resume (by playing) - flash._setPosition(s.id, position, (s.paused || !s.playState), s._iO.multiShot); - } - } else if(s._a) { - // Set the position in the canplay handler if the sound is not ready yet - if(s._html5_canplay) { - if(s._a.currentTime !== position1K) { - /** - * DOM/JS errors/exceptions to watch out for: - * if seek is beyond (loaded?) position, "DOM exception 11" - * "INDEX_SIZE_ERR": DOM exception 1 - */ - sm2._wD(s.id + ': setPosition(' + position1K + ')'); - try { - s._a.currentTime = position1K; - if(s.playState === 0 || s.paused) { - // allow seek without auto-play/resume - s._a.pause(); - } - } catch(e) { - sm2._wD(s.id + ': setPosition(' + position1K + ') failed: ' + e.message, 2); - } - } - } else if(position1K) { - // warn on non-zero seek attempts - sm2._wD(s.id + ': setPosition(' + position1K + '): Cannot seek yet, sound not ready', 2); - return s; - } - if(s.paused) { - // if paused, refresh UI right away - // force update - s._onTimer(true); - } - } - return s; - }; - /** - * Pauses sound playback. - * - * @return {SMSound} The SMSound object - */ - this.pause = function(_bCallFlash) { - if(s.paused || (s.playState === 0 && s.readyState !== 1)) { - return s; - } - sm2._wD(s.id + ': pause()'); - s.paused = true; - if(!s.isHTML5) { - if(_bCallFlash || _bCallFlash === _undefined) { - flash._pause(s.id, s._iO.multiShot); - } - } else { - s._setup_html5().pause(); - stop_html5_timer(); - } - if(s._iO.onpause) { - s._iO.onpause.apply(s); - } - return s; - }; - /** - * Resumes sound playback. - * - * @return {SMSound} The SMSound object - */ - /** - * When auto-loaded streams pause on buffer full they have a playState of 0. - * We need to make sure that the playState is set to 1 when these streams "resume". - * When a paused stream is resumed, we need to trigger the onplay() callback if it - * hasn't been called already. In this case since the sound is being played for the - * first time, I think it's more appropriate to call onplay() rather than onresume(). - */ - this.resume = function() { - var instanceOptions = s._iO; - if(!s.paused) { - return s; - } - sm2._wD(s.id + ': resume()'); - s.paused = false; - s.playState = 1; - if(!s.isHTML5) { - if(instanceOptions.isMovieStar && !instanceOptions.serverURL) { - // Bizarre Webkit bug (Chrome reported via 8tracks.com dudes): AAC content paused for 30+ seconds(?) will not resume without a reposition. - s.setPosition(s.position); - } - // flash method is toggle-based (pause/resume) - flash._pause(s.id, instanceOptions.multiShot); - } else { - s._setup_html5().play(); - start_html5_timer(); - } - if(!onplay_called && instanceOptions.onplay) { - instanceOptions.onplay.apply(s); - onplay_called = true; - } else if(instanceOptions.onresume) { - instanceOptions.onresume.apply(s); - } - return s; - }; - /** - * Toggles sound playback. - * - * @return {SMSound} The SMSound object - */ - this.togglePause = function() { - sm2._wD(s.id + ': togglePause()'); - if(s.playState === 0) { - s.play({ - position: (fV === 9 && !s.isHTML5 ? s.position : s.position / msecScale) - }); - return s; - } - if(s.paused) { - s.resume(); - } else { - s.pause(); - } - return s; - }; - /** - * Sets the panning (L-R) effect. - * - * @param {number} nPan The pan value (-100 to 100) - * @return {SMSound} The SMSound object - */ - this.setPan = function(nPan, bInstanceOnly) { - if(nPan === _undefined) { - nPan = 0; - } - if(bInstanceOnly === _undefined) { - bInstanceOnly = false; - } - if(!s.isHTML5) { - flash._setPan(s.id, nPan); - } // else { no HTML5 pan? } - s._iO.pan = nPan; - if(!bInstanceOnly) { - s.pan = nPan; - s.options.pan = nPan; - } - return s; - }; - /** - * Sets the volume. - * - * @param {number} nVol The volume value (0 to 100) - * @return {SMSound} The SMSound object - */ - this.setVolume = function(nVol, _bInstanceOnly) { - /** - * Note: Setting volume has no effect on iOS "special snowflake" devices. - * Hardware volume control overrides software, and volume - * will always return 1 per Apple docs. (iOS 4 + 5.) - * http://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/HTML-canvas-guide/AddingSoundtoCanvasAnimations/AddingSoundtoCanvasAnimations.html - */ - if(nVol === _undefined) { - nVol = 100; - } - if(_bInstanceOnly === _undefined) { - _bInstanceOnly = false; - } - if(!s.isHTML5) { - flash._setVolume(s.id, (sm2.muted && !s.muted) || s.muted ? 0 : nVol); - } else if(s._a) { - if(sm2.muted && !s.muted) { - s.muted = true; - s._a.muted = true; - } - // valid range: 0-1 - s._a.volume = Math.max(0, Math.min(1, nVol / 100)); - } - s._iO.volume = nVol; - if(!_bInstanceOnly) { - s.volume = nVol; - s.options.volume = nVol; - } - return s; - }; - /** - * Mutes the sound. - * - * @return {SMSound} The SMSound object - */ - this.mute = function() { - s.muted = true; - if(!s.isHTML5) { - flash._setVolume(s.id, 0); - } else if(s._a) { - s._a.muted = true; - } - return s; - }; - /** - * Unmutes the sound. - * - * @return {SMSound} The SMSound object - */ - this.unmute = function() { - s.muted = false; - var hasIO = (s._iO.volume !== _undefined); - if(!s.isHTML5) { - flash._setVolume(s.id, hasIO ? s._iO.volume : s.options.volume); - } else if(s._a) { - s._a.muted = false; - } - return s; - }; - /** - * Toggles the muted state of a sound. - * - * @return {SMSound} The SMSound object - */ - this.toggleMute = function() { - return(s.muted ? s.unmute() : s.mute()); - }; - /** - * Registers a callback to be fired when a sound reaches a given position during playback. - * - * @param {number} nPosition The position to watch for - * @param {function} oMethod The relevant callback to fire - * @param {object} oScope Optional: The scope to apply the callback to - * @return {SMSound} The SMSound object - */ - this.onPosition = function(nPosition, oMethod, oScope) { - // TODO: basic dupe checking? - onPositionItems.push({ - position: parseInt(nPosition, 10), - method: oMethod, - scope: (oScope !== _undefined ? oScope : s), - fired: false - }); - return s; - }; - // legacy/backwards-compability: lower-case method name - this.onposition = this.onPosition; - /** - * Removes registered callback(s) from a sound, by position and/or callback. - * - * @param {number} nPosition The position to clear callback(s) for - * @param {function} oMethod Optional: Identify one callback to be removed when multiple listeners exist for one position - * @return {SMSound} The SMSound object - */ - this.clearOnPosition = function(nPosition, oMethod) { - var i; - nPosition = parseInt(nPosition, 10); - if(isNaN(nPosition)) { - // safety check - return false; - } - for(i = 0; i < onPositionItems.length; i++) { - if(nPosition === onPositionItems[i].position) { - // remove this item if no method was specified, or, if the method matches - if(!oMethod || (oMethod === onPositionItems[i].method)) { - if(onPositionItems[i].fired) { - // decrement "fired" counter, too - onPositionFired--; - } - onPositionItems.splice(i, 1); - } - } - } - }; - this._processOnPosition = function() { - var i, item, j = onPositionItems.length; - if(!j || !s.playState || onPositionFired >= j) { - return false; - } - for(i = j - 1; i >= 0; i--) { - item = onPositionItems[i]; - if(!item.fired && s.position >= item.position) { - item.fired = true; - onPositionFired++; - item.method.apply(item.scope, [item.position]); - j = onPositionItems.length; // reset j -- onPositionItems.length can be changed in the item callback above... occasionally breaking the loop. - } - } - return true; + } + + if (oOptions && oOptions.url) { + // overloading use case, create+play: .play('someID', {url:'/path/to.mp3'}); + sm2._wD(sm + '.play(): Attempting to create "' + sID + '"', 1); + oOptions.id = sID; + result = sm2.createSound(oOptions).play(); + } + + } else if (overloaded) { + + // existing sound object case + oOptions = { + url: oOptions + }; + + } + + if (result === null) { + // default case + result = sm2.sounds[sID].play(oOptions); + } + + return result; + + }; + + // just for convenience + this.start = this.play; + + /** + * Calls the setPlaybackRate() method of a SMSound object by ID. + * + * @param {string} sID The ID of the sound + * @return {SMSound} The SMSound object + */ + + this.setPlaybackRate = function(sID, rate, allowOverride) { + + if (!idCheck(sID)) return false; + + return sm2.sounds[sID].setPlaybackRate(rate, allowOverride); + + }; + + /** + * Calls the setPosition() method of a SMSound object by ID. + * + * @param {string} sID The ID of the sound + * @param {number} nMsecOffset Position (milliseconds) + * @return {SMSound} The SMSound object + */ + + this.setPosition = function(sID, nMsecOffset) { + + if (!idCheck(sID)) return false; + + return sm2.sounds[sID].setPosition(nMsecOffset); + + }; + + /** + * Calls the stop() method of a SMSound object by ID. + * + * @param {string} sID The ID of the sound + * @return {SMSound} The SMSound object + */ + + this.stop = function(sID) { + + if (!idCheck(sID)) return false; + + sm2._wD(sm + '.stop(' + sID + ')', 1); + + return sm2.sounds[sID].stop(); + + }; + + /** + * Stops all currently-playing sounds. + */ + + this.stopAll = function() { + + var oSound; + sm2._wD(sm + '.stopAll()', 1); + + for (oSound in sm2.sounds) { + if (sm2.sounds.hasOwnProperty(oSound)) { + // apply only to sound objects + sm2.sounds[oSound].stop(); + } + } + + }; + + /** + * Calls the pause() method of a SMSound object by ID. + * + * @param {string} sID The ID of the sound + * @return {SMSound} The SMSound object + */ + + this.pause = function(sID) { + + if (!idCheck(sID)) return false; + + return sm2.sounds[sID].pause(); + + }; + + /** + * Pauses all currently-playing sounds. + */ + + this.pauseAll = function() { + + var i; + for (i = sm2.soundIDs.length - 1; i >= 0; i--) { + sm2.sounds[sm2.soundIDs[i]].pause(); + } + + }; + + /** + * Calls the resume() method of a SMSound object by ID. + * + * @param {string} sID The ID of the sound + * @return {SMSound} The SMSound object + */ + + this.resume = function(sID) { + + if (!idCheck(sID)) return false; + + return sm2.sounds[sID].resume(); + + }; + + /** + * Resumes all currently-paused sounds. + */ + + this.resumeAll = function() { + + var i; + for (i = sm2.soundIDs.length - 1; i >= 0; i--) { + sm2.sounds[sm2.soundIDs[i]].resume(); + } + + }; + + /** + * Calls the togglePause() method of a SMSound object by ID. + * + * @param {string} sID The ID of the sound + * @return {SMSound} The SMSound object + */ + + this.togglePause = function(sID) { + + if (!idCheck(sID)) return false; + + return sm2.sounds[sID].togglePause(); + + }; + + /** + * Calls the setPan() method of a SMSound object by ID. + * + * @param {string} sID The ID of the sound + * @param {number} nPan The pan value (-100 to 100) + * @return {SMSound} The SMSound object + */ + + this.setPan = function(sID, nPan) { + + if (!idCheck(sID)) return false; + + return sm2.sounds[sID].setPan(nPan); + + }; + + /** + * Calls the setVolume() method of a SMSound object by ID + * Overloaded case: pass only volume argument eg., setVolume(50) to apply to all sounds. + * + * @param {string} sID The ID of the sound + * @param {number} nVol The volume value (0 to 100) + * @return {SMSound} The SMSound object + */ + + this.setVolume = function(sID, nVol) { + + // setVolume(50) function overloading case - apply to all sounds + + var i, j; + + if (sID !== _undefined && !isNaN(sID) && nVol === _undefined) { + for (i = 0, j = sm2.soundIDs.length; i < j; i++) { + sm2.sounds[sm2.soundIDs[i]].setVolume(sID); + } + return false; + } + + // setVolume('mySound', 50) case + + if (!idCheck(sID)) return false; + + return sm2.sounds[sID].setVolume(nVol); + + }; + + /** + * Calls the mute() method of either a single SMSound object by ID, or all sound objects. + * + * @param {string} sID Optional: The ID of the sound (if omitted, all sounds will be used.) + */ + + this.mute = function(sID) { + + var i = 0; + + if (sID instanceof String) { + sID = null; + } + + if (!sID) { + + sm2._wD(sm + '.mute(): Muting all sounds'); + for (i = sm2.soundIDs.length - 1; i >= 0; i--) { + sm2.sounds[sm2.soundIDs[i]].mute(); + } + sm2.muted = true; + + } else { + + if (!idCheck(sID)) return false; + + sm2._wD(sm + '.mute(): Muting "' + sID + '"'); + return sm2.sounds[sID].mute(); + + } + + return true; + + }; + + /** + * Mutes all sounds. + */ + + this.muteAll = function() { + + sm2.mute(); + + }; + + /** + * Calls the unmute() method of either a single SMSound object by ID, or all sound objects. + * + * @param {string} sID Optional: The ID of the sound (if omitted, all sounds will be used.) + */ + + this.unmute = function(sID) { + + var i; + + if (sID instanceof String) { + sID = null; + } + + if (!sID) { + + sm2._wD(sm + '.unmute(): Unmuting all sounds'); + for (i = sm2.soundIDs.length - 1; i >= 0; i--) { + sm2.sounds[sm2.soundIDs[i]].unmute(); + } + sm2.muted = false; + + } else { + + if (!idCheck(sID)) return false; + + sm2._wD(sm + '.unmute(): Unmuting "' + sID + '"'); + + return sm2.sounds[sID].unmute(); + + } + + return true; + + }; + + /** + * Unmutes all sounds. + */ + + this.unmuteAll = function() { + + sm2.unmute(); + + }; + + /** + * Calls the toggleMute() method of a SMSound object by ID. + * + * @param {string} sID The ID of the sound + * @return {SMSound} The SMSound object + */ + + this.toggleMute = function(sID) { + + if (!idCheck(sID)) return false; + + return sm2.sounds[sID].toggleMute(); + + }; + + /** + * Retrieves the memory used by the flash plugin. + * + * @return {number} The amount of memory in use + */ + + this.getMemoryUse = function() { + + // flash-only + var ram = 0; + + if (flash && fV !== 8) { + ram = parseInt(flash._getMemoryUse(), 10); + } + + return ram; + + }; + + /** + * Undocumented: NOPs soundManager and all SMSound objects. + */ + + this.disable = function(bNoDisable) { + + // destroy all functions + var i; + + if (bNoDisable === _undefined) { + bNoDisable = false; + } + + // already disabled? + if (disabled) return false; + + disabled = true; + + _wDS('shutdown', 1); + + for (i = sm2.soundIDs.length - 1; i >= 0; i--) { + disableObject(sm2.sounds[sm2.soundIDs[i]]); + } + + disableObject(sm2); + + // fire "complete", despite fail + initComplete(bNoDisable); + + event.remove(window, 'load', initUserOnload); + + return true; + + }; + + /** + * Determines playability of a MIME type, eg. 'audio/mp3'. + */ + + this.canPlayMIME = function(sMIME) { + + var result; + + if (sm2.hasHTML5) { + result = html5CanPlay({ + type: sMIME + }); + } + + if (!result && needsFlash) { + // if flash 9, test netStream (movieStar) types as well. + result = (sMIME && sm2.ok() ? !!((fV > 8 ? sMIME.match(netStreamMimeTypes) : null) || sMIME.match(sm2.mimePattern)) : null); // TODO: make less "weird" (per JSLint) + } + + return result; + + }; + + /** + * Determines playability of a URL based on audio support. + * + * @param {string} sURL The URL to test + * @return {boolean} URL playability + */ + + this.canPlayURL = function(sURL) { + + var result; + + if (sm2.hasHTML5) { + result = html5CanPlay({ + url: sURL + }); + } + + if (!result && needsFlash) { + result = (sURL && sm2.ok() ? !!(sURL.match(sm2.filePattern)) : null); + } + + return result; + + }; + + /** + * Determines playability of an HTML DOM <a> object (or similar object literal) based on audio support. + * + * @param {object} oLink an HTML DOM <a> object or object literal including href and/or type attributes + * @return {boolean} URL playability + */ + + this.canPlayLink = function(oLink) { + + if (oLink.type !== _undefined && oLink.type && sm2.canPlayMIME(oLink.type)) return true; + + return sm2.canPlayURL(oLink.href); + + }; + + /** + * Retrieves a SMSound object by ID. + * + * @param {string} sID The ID of the sound + * @return {SMSound} The SMSound object + */ + + this.getSoundById = function(sID, _suppressDebug) { + + if (!sID) return null; + + var result = sm2.sounds[sID]; + + // + if (!result && !_suppressDebug) { + sm2._wD(sm + '.getSoundById(): Sound "' + sID + '" not found.', 2); + } + // + + return result; + + }; + + /** + * Queues a callback for execution when SoundManager has successfully initialized. + * + * @param {function} oMethod The callback method to fire + * @param {object} oScope Optional: The scope to apply to the callback + */ + + this.onready = function(oMethod, oScope) { + + var sType = 'onready', + result = false; + + if (typeof oMethod === 'function') { + + // + if (didInit) { + sm2._wD(str('queue', sType)); + } + // + + if (!oScope) { + oScope = window; + } + + addOnEvent(sType, oMethod, oScope); + processOnEvents(); + + result = true; + + } else { + + throw str('needFunction', sType); + + } + + return result; + + }; + + /** + * Queues a callback for execution when SoundManager has failed to initialize. + * + * @param {function} oMethod The callback method to fire + * @param {object} oScope Optional: The scope to apply to the callback + */ + + this.ontimeout = function(oMethod, oScope) { + + var sType = 'ontimeout', + result = false; + + if (typeof oMethod === 'function') { + + // + if (didInit) { + sm2._wD(str('queue', sType)); + } + // + + if (!oScope) { + oScope = window; + } + + addOnEvent(sType, oMethod, oScope); + processOnEvents({ type: sType }); + + result = true; + + } else { + + throw str('needFunction', sType); + + } + + return result; + + }; + + /** + * Writes console.log()-style debug output to a console or in-browser element. + * Applies when debugMode = true + * + * @param {string} sText The console message + * @param {object} nType Optional log level (number), or object. Number case: Log type/style where 0 = 'info', 1 = 'warn', 2 = 'error'. Object case: Object to be dumped. + */ + + this._writeDebug = function(sText, sTypeOrObject) { + + // pseudo-private console.log()-style output + // + + var sDID = 'soundmanager-debug', o, oItem; + + if (!sm2.setupOptions.debugMode) return false; + + if (hasConsole && sm2.useConsole) { + if (sTypeOrObject && typeof sTypeOrObject === 'object') { + // object passed; dump to console. + console.log(sText, sTypeOrObject); + } else if (debugLevels[sTypeOrObject] !== _undefined) { + console[debugLevels[sTypeOrObject]](sText); + } else { + console.log(sText); + } + if (sm2.consoleOnly) return true; + } + + o = id(sDID); + + if (!o) return false; + + oItem = doc.createElement('div'); + + if (++wdCount % 2 === 0) { + oItem.className = 'sm2-alt'; + } + + if (sTypeOrObject === _undefined) { + sTypeOrObject = 0; + } else { + sTypeOrObject = parseInt(sTypeOrObject, 10); + } + + oItem.appendChild(doc.createTextNode(sText)); + + if (sTypeOrObject) { + if (sTypeOrObject >= 2) { + oItem.style.fontWeight = 'bold'; + } + if (sTypeOrObject === 3) { + oItem.style.color = '#ff3333'; + } + } + + // top-to-bottom + // o.appendChild(oItem); + + // bottom-to-top + o.insertBefore(oItem, o.firstChild); + + o = null; + // + + return true; + + }; + + // + // last-resort debugging option + if (wl.indexOf('sm2-debug=alert') !== -1) { + this._writeDebug = function(sText) { + window.alert(sText); + }; + } + // + + // alias + this._wD = this._writeDebug; + + /** + * Provides debug / state information on all SMSound objects. + */ + + this._debug = function() { + + // + var i, j; + _wDS('currentObj', 1); + + for (i = 0, j = sm2.soundIDs.length; i < j; i++) { + sm2.sounds[sm2.soundIDs[i]]._debug(); + } + // + + }; + + /** + * Restarts and re-initializes the SoundManager instance. + * + * @param {boolean} resetEvents Optional: When true, removes all registered onready and ontimeout event callbacks. + * @param {boolean} excludeInit Options: When true, does not call beginDelayedInit() (which would restart SM2). + * @return {object} soundManager The soundManager instance. + */ + + this.reboot = function(resetEvents, excludeInit) { + + // reset some (or all) state, and re-init unless otherwise specified. + + // + if (sm2.soundIDs.length) { + sm2._wD('Destroying ' + sm2.soundIDs.length + ' SMSound object' + (sm2.soundIDs.length !== 1 ? 's' : '') + '...'); + } + // + + var i, j, k; + + for (i = sm2.soundIDs.length - 1; i >= 0; i--) { + sm2.sounds[sm2.soundIDs[i]].destruct(); + } + + // trash ze flash (remove from the DOM) + + if (flash) { + + try { + + if (isIE) { + oRemovedHTML = flash.innerHTML; + } + + oRemoved = flash.parentNode.removeChild(flash); + + } catch(e) { + + // Remove failed? May be due to flash blockers silently removing the SWF object/embed node from the DOM. Warn and continue. + + _wDS('badRemove', 2); + + } + + } + + // actually, force recreate of movie. + + oRemovedHTML = oRemoved = needsFlash = flash = null; + + sm2.enabled = didDCLoaded = didInit = waitingForEI = initPending = didAppend = appendSuccess = disabled = useGlobalHTML5Audio = sm2.swfLoaded = false; + + sm2.soundIDs = []; + sm2.sounds = {}; + + idCounter = 0; + didSetup = false; + + if (!resetEvents) { + // reset callbacks for onready, ontimeout etc. so that they will fire again on re-init + for (i in on_queue) { + if (on_queue.hasOwnProperty(i)) { + for (j = 0, k = on_queue[i].length; j < k; j++) { + on_queue[i][j].fired = false; + } + } + } + } else { + // remove all callbacks entirely + on_queue = []; + } + + // + if (!excludeInit) { + sm2._wD(sm + ': Rebooting...'); + } + // + + // reset HTML5 and flash canPlay test results + + sm2.html5 = { + usingFlash: null + }; + + sm2.flash = {}; + + // reset device-specific HTML/flash mode switches + + sm2.html5Only = false; + sm2.ignoreFlash = false; + + window.setTimeout(function() { + + // by default, re-init + + if (!excludeInit) { + sm2.beginDelayedInit(); + } + + }, 20); + + return sm2; + + }; + + this.reset = function() { + + /** + * Shuts down and restores the SoundManager instance to its original loaded state, without an explicit reboot. All onready/ontimeout handlers are removed. + * After this call, SM2 may be re-initialized via soundManager.beginDelayedInit(). + * @return {object} soundManager The soundManager instance. + */ + + _wDS('reset'); + + return sm2.reboot(true, true); + + }; + + /** + * Undocumented: Determines the SM2 flash movie's load progress. + * + * @return {number or null} Percent loaded, or if invalid/unsupported, null. + */ + + this.getMoviePercent = function() { + + /** + * Interesting syntax notes... + * Flash/ExternalInterface (ActiveX/NPAPI) bridge methods are not typeof "function" nor instanceof Function, but are still valid. + * Furthermore, using (flash && flash.PercentLoaded) causes IE to throw "object doesn't support this property or method". + * Thus, 'in' syntax must be used. + */ + + return (flash && 'PercentLoaded' in flash ? flash.PercentLoaded() : null); + + }; + + /** + * Additional helper for manually invoking SM2's init process after DOM Ready / window.onload(). + */ + + this.beginDelayedInit = function() { + + windowLoaded = true; + domContentLoaded(); + + setTimeout(function() { + + if (initPending) return false; + + createMovie(); + initMovie(); + initPending = true; + + return true; + + }, 20); + + delayWaitForEI(); + + }; + + /** + * Destroys the SoundManager instance and all SMSound instances. + */ + + this.destruct = function() { + + sm2._wD(sm + '.destruct()'); + sm2.disable(true); + + }; + + /** + * SMSound() (sound object) constructor + * ------------------------------------ + * + * @param {object} oOptions Sound options (id and url are required attributes) + * @return {SMSound} The new SMSound object + */ + + SMSound = function(oOptions) { + + var s = this, resetProperties, add_html5_events, remove_html5_events, stop_html5_timer, start_html5_timer, attachOnPosition, onplay_called = false, onPositionItems = [], onPositionFired = 0, detachOnPosition, applyFromTo, lastURL = null, lastHTML5State, urlOmitted; + + lastHTML5State = { + // tracks duration + position (time) + duration: null, + time: null + }; + + this.id = oOptions.id; + + // legacy + this.sID = this.id; + + this.url = oOptions.url; + this.options = mixin(oOptions); + + // per-play-instance-specific options + this.instanceOptions = this.options; + + // short alias + this._iO = this.instanceOptions; + + // assign property defaults + this.pan = this.options.pan; + this.volume = this.options.volume; + + // whether or not this object is using HTML5 + this.isHTML5 = false; + + // internal HTML5 Audio() object reference + this._a = null; + + // for flash 8 special-case createSound() without url, followed by load/play with url case + urlOmitted = (!this.url); + + /** + * SMSound() public methods + * ------------------------ + */ + + this.id3 = {}; + + /** + * Writes SMSound object parameters to debug console + */ + + this._debug = function() { + + // + sm2._wD(s.id + ': Merged options:', s.options); + // + + }; + + /** + * Begins loading a sound per its *url*. + * + * @param {object} options Optional: Sound options + * @return {SMSound} The SMSound object + */ + + this.load = function(options) { + + var oSound = null, instanceOptions; + + if (options !== _undefined) { + s._iO = mixin(options, s.options); + } else { + options = s.options; + s._iO = options; + if (lastURL && lastURL !== s.url) { + _wDS('manURL'); + s._iO.url = s.url; + s.url = null; + } + } + + if (!s._iO.url) { + s._iO.url = s.url; + } + + s._iO.url = parseURL(s._iO.url); + + // ensure we're in sync + s.instanceOptions = s._iO; + + // local shortcut + instanceOptions = s._iO; + + sm2._wD(s.id + ': load (' + instanceOptions.url + ')'); + + if (!instanceOptions.url && !s.url) { + sm2._wD(s.id + ': load(): url is unassigned. Exiting.', 2); + return s; + } + + // + if (!s.isHTML5 && fV === 8 && !s.url && !instanceOptions.autoPlay) { + // flash 8 load() -> play() won't work before onload has fired. + sm2._wD(s.id + ': Flash 8 load() limitation: Wait for onload() before calling play().', 1); + } + // + + if (instanceOptions.url === s.url && s.readyState !== 0 && s.readyState !== 2) { + _wDS('onURL', 1); + // if loaded and an onload() exists, fire immediately. + if (s.readyState === 3 && instanceOptions.onload) { + // assume success based on truthy duration. + wrapCallback(s, function() { + instanceOptions.onload.apply(s, [(!!s.duration)]); + }); + } + return s; + } + + // reset a few state properties + + s.loaded = false; + s.readyState = 1; + s.playState = 0; + s.id3 = {}; + + // TODO: If switching from HTML5 -> flash (or vice versa), stop currently-playing audio. + + if (html5OK(instanceOptions)) { + + oSound = s._setup_html5(instanceOptions); + + if (!oSound._called_load) { + + s._html5_canplay = false; + + // TODO: review called_load / html5_canplay logic + + // if url provided directly to load(), assign it here. + + if (s.url !== instanceOptions.url) { + + sm2._wD(_wDS('manURL') + ': ' + instanceOptions.url); + + s._a.src = instanceOptions.url; + + // TODO: review / re-apply all relevant options (volume, loop, onposition etc.) + + // reset position for new URL + s.setPosition(0); + + } + + // given explicit load call, try to preload. + + // early HTML5 implementation (non-standard) + s._a.autobuffer = 'auto'; + + // standard property, values: none / metadata / auto + // reference: http://msdn.microsoft.com/en-us/library/ie/ff974759%28v=vs.85%29.aspx + s._a.preload = 'auto'; + + s._a._called_load = true; + + } else { + + sm2._wD(s.id + ': Ignoring request to load again'); + + } + + } else { + + if (sm2.html5Only) { + sm2._wD(s.id + ': No flash support. Exiting.'); + return s; + } + + if (s._iO.url && s._iO.url.match(/data:/i)) { + // data: URIs not supported by Flash, either. + sm2._wD(s.id + ': data: URIs not supported via Flash. Exiting.'); + return s; + } + + try { + s.isHTML5 = false; + s._iO = policyFix(loopFix(instanceOptions)); + // if we have "position", disable auto-play as we'll be seeking to that position at onload(). + if (s._iO.autoPlay && (s._iO.position || s._iO.from)) { + sm2._wD(s.id + ': Disabling autoPlay because of non-zero offset case'); + s._iO.autoPlay = false; + } + // re-assign local shortcut + instanceOptions = s._iO; + if (fV === 8) { + flash._load(s.id, instanceOptions.url, instanceOptions.stream, instanceOptions.autoPlay, instanceOptions.usePolicyFile); + } else { + flash._load(s.id, instanceOptions.url, !!(instanceOptions.stream), !!(instanceOptions.autoPlay), instanceOptions.loops || 1, !!(instanceOptions.autoLoad), instanceOptions.usePolicyFile); + } + } catch(e) { + _wDS('smError', 2); + debugTS('onload', false); + catchError({ + type: 'SMSOUND_LOAD_JS_EXCEPTION', + fatal: true + }); + } + + } + + // after all of this, ensure sound url is up to date. + s.url = instanceOptions.url; + + return s; + + }; + + /** + * Unloads a sound, canceling any open HTTP requests. + * + * @return {SMSound} The SMSound object + */ + + this.unload = function() { + + // Flash 8/AS2 can't "close" a stream - fake it by loading an empty URL + // Flash 9/AS3: Close stream, preventing further load + // HTML5: Most UAs will use empty URL + + if (s.readyState !== 0) { + + sm2._wD(s.id + ': unload()'); + + if (!s.isHTML5) { + + if (fV === 8) { + flash._unload(s.id, emptyURL); + } else { + flash._unload(s.id); + } + + } else { + + stop_html5_timer(); + + if (s._a) { + + s._a.pause(); + + // update empty URL, too + lastURL = html5Unload(s._a); + + } + + } + + // reset load/status flags + resetProperties(); + + } + + return s; + + }; + + /** + * Unloads and destroys a sound. + */ + + this.destruct = function(_bFromSM) { + + sm2._wD(s.id + ': Destruct'); + + if (!s.isHTML5) { + + // kill sound within Flash + // Disable the onfailure handler + s._iO.onfailure = null; + flash._destroySound(s.id); + + } else { + + stop_html5_timer(); + + if (s._a) { + s._a.pause(); + html5Unload(s._a); + if (!useGlobalHTML5Audio) { + remove_html5_events(); + } + // break obvious circular reference + s._a._s = null; + s._a = null; + } + + } + + if (!_bFromSM) { + // ensure deletion from controller + sm2.destroySound(s.id, true); + } + + }; + + /** + * Begins playing a sound. + * + * @param {object} options Optional: Sound options + * @return {SMSound} The SMSound object + */ + + this.play = function(options, _updatePlayState) { + + var fN, allowMulti, a, onready, + audioClone, onended, oncanplay, + startOK = true; + + // + fN = s.id + ': play(): '; + // + + // default to true + _updatePlayState = (_updatePlayState === _undefined ? true : _updatePlayState); + + if (!options) { + options = {}; + } + + // first, use local URL (if specified) + if (s.url) { + s._iO.url = s.url; + } + + // mix in any options defined at createSound() + s._iO = mixin(s._iO, s.options); + + // mix in any options specific to this method + s._iO = mixin(options, s._iO); + + s._iO.url = parseURL(s._iO.url); + + s.instanceOptions = s._iO; + + // RTMP-only + if (!s.isHTML5 && s._iO.serverURL && !s.connected) { + if (!s.getAutoPlay()) { + sm2._wD(fN + ' Netstream not connected yet - setting autoPlay'); + s.setAutoPlay(true); + } + // play will be called in onconnect() + return s; + } + + if (html5OK(s._iO)) { + s._setup_html5(s._iO); + start_html5_timer(); + } + + if (s.playState === 1 && !s.paused) { + + allowMulti = s._iO.multiShot; + + if (!allowMulti) { + + sm2._wD(fN + 'Already playing (one-shot)', 1); + + if (s.isHTML5) { + // go back to original position. + s.setPosition(s._iO.position); + } + + return s; + + } + + sm2._wD(fN + 'Already playing (multi-shot)', 1); + + } + + // edge case: play() with explicit URL parameter + if (options.url && options.url !== s.url) { + + // special case for createSound() followed by load() / play() with url; avoid double-load case. + if (!s.readyState && !s.isHTML5 && fV === 8 && urlOmitted) { + + urlOmitted = false; + + } else { + + // load using merged options + s.load(s._iO); + + } + + } + + if (!s.loaded) { + + if (s.readyState === 0) { + + sm2._wD(fN + 'Attempting to load'); + + // try to get this sound playing ASAP + if (!s.isHTML5 && !sm2.html5Only) { + + // flash: assign directly because setAutoPlay() increments the instanceCount + s._iO.autoPlay = true; + s.load(s._iO); + + } else if (s.isHTML5) { + + // iOS needs this when recycling sounds, loading a new URL on an existing object. + s.load(s._iO); + + } else { + + sm2._wD(fN + 'Unsupported type. Exiting.'); + + return s; + + } + + // HTML5 hack - re-set instanceOptions? + s.instanceOptions = s._iO; + + } else if (s.readyState === 2) { + + sm2._wD(fN + 'Could not load - exiting', 2); + + return s; + + } else { + + sm2._wD(fN + 'Loading - attempting to play...'); + + } + + } else { + + // "play()" + sm2._wD(fN.substr(0, fN.lastIndexOf(':'))); + + } + + if (!s.isHTML5 && fV === 9 && s.position > 0 && s.position === s.duration) { + // flash 9 needs a position reset if play() is called while at the end of a sound. + sm2._wD(fN + 'Sound at end, resetting to position: 0'); + options.position = 0; + } + + /** + * Streams will pause when their buffer is full if they are being loaded. + * In this case paused is true, but the song hasn't started playing yet. + * If we just call resume() the onplay() callback will never be called. + * So only call resume() if the position is > 0. + * Another reason is because options like volume won't have been applied yet. + * For normal sounds, just resume. + */ + + if (s.paused && s.position >= 0 && (!s._iO.serverURL || s.position > 0)) { + + // https://gist.github.com/37b17df75cc4d7a90bf6 + sm2._wD(fN + 'Resuming from paused state', 1); + s.resume(); + + } else { + + s._iO = mixin(options, s._iO); + + /** + * Preload in the event of play() with position under Flash, + * or from/to parameters and non-RTMP case + */ + if (((!s.isHTML5 && s._iO.position !== null && s._iO.position > 0) || (s._iO.from !== null && s._iO.from > 0) || s._iO.to !== null) && s.instanceCount === 0 && s.playState === 0 && !s._iO.serverURL) { + + onready = function() { + // sound "canplay" or onload() + // re-apply position/from/to to instance options, and start playback + s._iO = mixin(options, s._iO); + s.play(s._iO); + }; + + // HTML5 needs to at least have "canplay" fired before seeking. + if (s.isHTML5 && !s._html5_canplay) { + + // this hasn't been loaded yet. load it first, and then do this again. + sm2._wD(fN + 'Beginning load for non-zero offset case'); + + s.load({ + // note: custom HTML5-only event added for from/to implementation. + _oncanplay: onready + }); + + } else if (!s.isHTML5 && !s.loaded && (!s.readyState || s.readyState !== 2)) { + + // to be safe, preload the whole thing in Flash. + + sm2._wD(fN + 'Preloading for non-zero offset case'); + + s.load({ + onload: onready + }); + + } + + // otherwise, we're ready to go. re-apply local options, and continue + + s._iO = applyFromTo(); + + } + + // sm2._wD(fN + 'Starting to play'); + + // increment instance counter, where enabled + supported + if (!s.instanceCount || s._iO.multiShotEvents || (s.isHTML5 && s._iO.multiShot && !useGlobalHTML5Audio) || (!s.isHTML5 && fV > 8 && !s.getAutoPlay())) { + s.instanceCount++; + } + + // if first play and onposition parameters exist, apply them now + if (s._iO.onposition && s.playState === 0) { + attachOnPosition(s); + } + + s.playState = 1; + s.paused = false; + + s.position = (s._iO.position !== _undefined && !isNaN(s._iO.position) ? s._iO.position : 0); + + if (!s.isHTML5) { + s._iO = policyFix(loopFix(s._iO)); + } + + if (s._iO.onplay && _updatePlayState) { + s._iO.onplay.apply(s); + onplay_called = true; + } + + s.setVolume(s._iO.volume, true); + s.setPan(s._iO.pan, true); + + if (s._iO.playbackRate !== 1) { + s.setPlaybackRate(s._iO.playbackRate); + } + + if (!s.isHTML5) { + + startOK = flash._start(s.id, s._iO.loops || 1, (fV === 9 ? s.position : s.position / msecScale), s._iO.multiShot || false); + + if (fV === 9 && !startOK) { + // edge case: no sound hardware, or 32-channel flash ceiling hit. + // applies only to Flash 9, non-NetStream/MovieStar sounds. + // http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/Sound.html#play%28%29 + sm2._wD(fN + 'No sound hardware, or 32-sound ceiling hit', 2); + if (s._iO.onplayerror) { + s._iO.onplayerror.apply(s); + } + + } + + } else if (s.instanceCount < 2) { + + // HTML5 single-instance case + + start_html5_timer(); + + a = s._setup_html5(); + + s.setPosition(s._iO.position); + + a.play(); + + } else { + + // HTML5 multi-shot case + + sm2._wD(s.id + ': Cloning Audio() for instance #' + s.instanceCount + '...'); + + audioClone = new Audio(s._iO.url); + + onended = function() { + event.remove(audioClone, 'ended', onended); + s._onfinish(s); + // cleanup + html5Unload(audioClone); + audioClone = null; }; - this._resetOnPosition = function(nPosition) { - // reset "fired" for items interested in this position - var i, item, j = onPositionItems.length; - if(!j) { - return false; - } - for(i = j - 1; i >= 0; i--) { - item = onPositionItems[i]; - if(item.fired && nPosition <= item.position) { - item.fired = false; - onPositionFired--; - } - } - return true; + + oncanplay = function() { + event.remove(audioClone, 'canplay', oncanplay); + try { + audioClone.currentTime = s._iO.position / msecScale; + } catch(err) { + complain(s.id + ': multiShot play() failed to apply position of ' + (s._iO.position / msecScale)); + } + audioClone.play(); }; + + event.add(audioClone, 'ended', onended); + + // apply volume to clones, too + if (s._iO.volume !== _undefined) { + audioClone.volume = Math.max(0, Math.min(1, s._iO.volume / 100)); + } + + // playing multiple muted sounds? if you do this, you're weird ;) - but let's cover it. + if (s.muted) { + audioClone.muted = true; + } + + if (s._iO.position) { + // HTML5 audio can't seek before onplay() event has fired. + // wait for canplay, then seek to position and start playback. + event.add(audioClone, 'canplay', oncanplay); + } else { + // begin playback at currentTime: 0 + audioClone.play(); + } + + } + + } + + return s; + + }; + + // just for convenience + this.start = this.play; + + /** + * Stops playing a sound (and optionally, all sounds) + * + * @param {boolean} bAll Optional: Whether to stop all sounds + * @return {SMSound} The SMSound object + */ + + this.stop = function(bAll) { + + var instanceOptions = s._iO, + originalPosition; + + if (s.playState === 1) { + + sm2._wD(s.id + ': stop()'); + + s._onbufferchange(0); + s._resetOnPosition(0); + s.paused = false; + + if (!s.isHTML5) { + s.playState = 0; + } + + // remove onPosition listeners, if any + detachOnPosition(); + + // and "to" position, if set + if (instanceOptions.to) { + s.clearOnPosition(instanceOptions.to); + } + + if (!s.isHTML5) { + + flash._stop(s.id, bAll); + + // hack for netStream: just unload + if (instanceOptions.serverURL) { + s.unload(); + } + + } else if (s._a) { + + originalPosition = s.position; + + // act like Flash, though + s.setPosition(0); + + // hack: reflect old position for onstop() (also like Flash) + s.position = originalPosition; + + // html5 has no stop() + // NOTE: pausing means iOS requires interaction to resume. + s._a.pause(); + + s.playState = 0; + + // and update UI + s._onTimer(); + + stop_html5_timer(); + + } + + s.instanceCount = 0; + s._iO = {}; + + if (instanceOptions.onstop) { + instanceOptions.onstop.apply(s); + } + + } + + return s; + + }; + + /** + * Undocumented/internal: Sets autoPlay for RTMP. + * + * @param {boolean} autoPlay state + */ + + this.setAutoPlay = function(autoPlay) { + + sm2._wD(s.id + ': Autoplay turned ' + (autoPlay ? 'on' : 'off')); + s._iO.autoPlay = autoPlay; + + if (!s.isHTML5) { + flash._setAutoPlay(s.id, autoPlay); + if (autoPlay) { + // only increment the instanceCount if the sound isn't loaded (TODO: verify RTMP) + if (!s.instanceCount && s.readyState === 1) { + s.instanceCount++; + sm2._wD(s.id + ': Incremented instance count to ' + s.instanceCount); + } + } + } + + }; + + /** + * Undocumented/internal: Returns the autoPlay boolean. + * + * @return {boolean} The current autoPlay value + */ + + this.getAutoPlay = function() { + + return s._iO.autoPlay; + + }; + + /** + * Sets the playback rate of a sound (HTML5-only.) + * + * @param {number} playbackRate (+/-) + * @return {SMSound} The SMSound object + */ + + this.setPlaybackRate = function(playbackRate) { + + // Per Mozilla, limit acceptable values to prevent playback from stopping (unless allowOverride is truthy.) + // https://developer.mozilla.org/en-US/Apps/Build/Audio_and_video_delivery/WebAudio_playbackRate_explained + var normalizedRate = Math.max(0.5, Math.min(4, playbackRate)); + + // + if (normalizedRate !== playbackRate) { + sm2._wD(s.id + ': setPlaybackRate(' + playbackRate + '): limiting rate to ' + normalizedRate, 2); + } + // + + if (s.isHTML5) { + try { + s._iO.playbackRate = normalizedRate; + s._a.playbackRate = normalizedRate; + } catch(e) { + sm2._wD(s.id + ': setPlaybackRate(' + normalizedRate + ') failed: ' + e.message, 2); + } + } + + return s; + + }; + + /** + * Sets the position of a sound. + * + * @param {number} nMsecOffset Position (milliseconds) + * @return {SMSound} The SMSound object + */ + + this.setPosition = function(nMsecOffset) { + + if (nMsecOffset === _undefined) { + nMsecOffset = 0; + } + + var position, position1K, + // Use the duration from the instance options, if we don't have a track duration yet. + // position >= 0 and <= current available (loaded) duration + offset = (s.isHTML5 ? Math.max(nMsecOffset, 0) : Math.min(s.duration || s._iO.duration, Math.max(nMsecOffset, 0))); + + s.position = offset; + position1K = s.position / msecScale; + s._resetOnPosition(s.position); + s._iO.position = offset; + + if (!s.isHTML5) { + + position = (fV === 9 ? s.position : position1K); + + if (s.readyState && s.readyState !== 2) { + // if paused or not playing, will not resume (by playing) + flash._setPosition(s.id, position, (s.paused || !s.playState), s._iO.multiShot); + } + + } else if (s._a) { + + // Set the position in the canplay handler if the sound is not ready yet + if (s._html5_canplay) { + + if (s._a.currentTime.toFixed(3) !== position1K.toFixed(3)) { + /** - * SMSound() private internals - * -------------------------------- + * DOM/JS errors/exceptions to watch out for: + * if seek is beyond (loaded?) position, "DOM exception 11" + * "INDEX_SIZE_ERR": DOM exception 1 */ - applyFromTo = function() { - var instanceOptions = s._iO, - f = instanceOptions.from, - t = instanceOptions.to, - start, end; - end = function() { - // end has been reached. - sm2._wD(s.id + ': "To" time of ' + t + ' reached.'); - // detach listener - s.clearOnPosition(t, end); - // stop should clear this, too - s.stop(); - }; - start = function() { - sm2._wD(s.id + ': Playing "from" ' + f); - // add listener for end - if(t !== null && !isNaN(t)) { - s.onPosition(t, end); - } - }; - if(f !== null && !isNaN(f)) { - // apply to instance options, guaranteeing correct start position. - instanceOptions.position = f; - // multiShot timing can't be tracked, so prevent that. - instanceOptions.multiShot = false; - start(); - } - // return updated instanceOptions including starting position - return instanceOptions; - }; - attachOnPosition = function() { - var item, - op = s._iO.onposition; - // attach onposition things, if any, now. - if(op) { - for(item in op) { - if(op.hasOwnProperty(item)) { - s.onPosition(parseInt(item, 10), op[item]); - } - } - } - }; - detachOnPosition = function() { - var item, - op = s._iO.onposition; - // detach any onposition()-style listeners. - if(op) { - for(item in op) { - if(op.hasOwnProperty(item)) { - s.clearOnPosition(parseInt(item, 10)); - } - } - } - }; - start_html5_timer = function() { - if(s.isHTML5) { - startTimer(s); - } - }; - stop_html5_timer = function() { - if(s.isHTML5) { - stopTimer(s); - } - }; - resetProperties = function(retainPosition) { - if(!retainPosition) { - onPositionItems = []; - onPositionFired = 0; - } - onplay_called = false; - s._hasTimer = null; - s._a = null; - s._html5_canplay = false; - s.bytesLoaded = null; - s.bytesTotal = null; - s.duration = (s._iO && s._iO.duration ? s._iO.duration : null); - s.durationEstimate = null; - s.buffered = []; - // legacy: 1D array - s.eqData = []; - s.eqData.left = []; - s.eqData.right = []; - s.failures = 0; - s.isBuffering = false; - s.instanceOptions = {}; - s.instanceCount = 0; - s.loaded = false; - s.metadata = {}; - // 0 = uninitialised, 1 = loading, 2 = failed/error, 3 = loaded/success - s.readyState = 0; - s.muted = false; - s.paused = false; - s.peakData = { - left: 0, - right: 0 - }; - s.waveformData = { - left: [], - right: [] - }; - s.playState = 0; - s.position = null; - s.id3 = {}; - }; - resetProperties(); + sm2._wD(s.id + ': setPosition(' + position1K + ')'); + + try { + s._a.currentTime = position1K; + if (s.playState === 0 || s.paused) { + // allow seek without auto-play/resume + s._a.pause(); + } + } catch(e) { + sm2._wD(s.id + ': setPosition(' + position1K + ') failed: ' + e.message, 2); + } + + } + + } else if (position1K) { + + // warn on non-zero seek attempts + sm2._wD(s.id + ': setPosition(' + position1K + '): Cannot seek yet, sound not ready', 2); + return s; + + } + + if (s.paused) { + + // if paused, refresh UI right away by forcing update + s._onTimer(true); + + } + + } + + return s; + + }; + + /** + * Pauses sound playback. + * + * @return {SMSound} The SMSound object + */ + + this.pause = function(_bCallFlash) { + + if (s.paused || (s.playState === 0 && s.readyState !== 1)) return s; + + sm2._wD(s.id + ': pause()'); + s.paused = true; + + if (!s.isHTML5) { + if (_bCallFlash || _bCallFlash === _undefined) { + flash._pause(s.id, s._iO.multiShot); + } + } else { + s._setup_html5().pause(); + stop_html5_timer(); + } + + if (s._iO.onpause) { + s._iO.onpause.apply(s); + } + + return s; + + }; + + /** + * Resumes sound playback. + * + * @return {SMSound} The SMSound object + */ + + /** + * When auto-loaded streams pause on buffer full they have a playState of 0. + * We need to make sure that the playState is set to 1 when these streams "resume". + * When a paused stream is resumed, we need to trigger the onplay() callback if it + * hasn't been called already. In this case since the sound is being played for the + * first time, I think it's more appropriate to call onplay() rather than onresume(). + */ + + this.resume = function() { + + var instanceOptions = s._iO; + + if (!s.paused) return s; + + sm2._wD(s.id + ': resume()'); + s.paused = false; + s.playState = 1; + + if (!s.isHTML5) { + + if (instanceOptions.isMovieStar && !instanceOptions.serverURL) { + // Bizarre Webkit bug (Chrome reported via 8tracks.com dudes): AAC content paused for 30+ seconds(?) will not resume without a reposition. + s.setPosition(s.position); + } + + // flash method is toggle-based (pause/resume) + flash._pause(s.id, instanceOptions.multiShot); + + } else { + + s._setup_html5().play(); + start_html5_timer(); + + } + + if (!onplay_called && instanceOptions.onplay) { + + instanceOptions.onplay.apply(s); + onplay_called = true; + + } else if (instanceOptions.onresume) { + + instanceOptions.onresume.apply(s); + + } + + return s; + + }; + + /** + * Toggles sound playback. + * + * @return {SMSound} The SMSound object + */ + + this.togglePause = function() { + + sm2._wD(s.id + ': togglePause()'); + + if (s.playState === 0) { + s.play({ + position: (fV === 9 && !s.isHTML5 ? s.position : s.position / msecScale) + }); + return s; + } + + if (s.paused) { + s.resume(); + } else { + s.pause(); + } + + return s; + + }; + + /** + * Sets the panning (L-R) effect. + * + * @param {number} nPan The pan value (-100 to 100) + * @return {SMSound} The SMSound object + */ + + this.setPan = function(nPan, bInstanceOnly) { + + if (nPan === _undefined) { + nPan = 0; + } + + if (bInstanceOnly === _undefined) { + bInstanceOnly = false; + } + + if (!s.isHTML5) { + flash._setPan(s.id, nPan); + } // else { no HTML5 pan? } + + s._iO.pan = nPan; + + if (!bInstanceOnly) { + s.pan = nPan; + s.options.pan = nPan; + } + + return s; + + }; + + /** + * Sets the volume. + * + * @param {number} nVol The volume value (0 to 100) + * @return {SMSound} The SMSound object + */ + + this.setVolume = function(nVol, _bInstanceOnly) { + + /** + * Note: Setting volume has no effect on iOS "special snowflake" devices. + * Hardware volume control overrides software, and volume + * will always return 1 per Apple docs. (iOS 4 + 5.) + * http://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/HTML-canvas-guide/AddingSoundtoCanvasAnimations/AddingSoundtoCanvasAnimations.html + */ + + if (nVol === _undefined) { + nVol = 100; + } + + if (_bInstanceOnly === _undefined) { + _bInstanceOnly = false; + } + + if (!s.isHTML5) { + + flash._setVolume(s.id, (sm2.muted && !s.muted) || s.muted ? 0 : nVol); + + } else if (s._a) { + + if (sm2.muted && !s.muted) { + s.muted = true; + s._a.muted = true; + } + + // valid range for native HTML5 Audio(): 0-1 + s._a.volume = Math.max(0, Math.min(1, nVol / 100)); + + } + + s._iO.volume = nVol; + + if (!_bInstanceOnly) { + s.volume = nVol; + s.options.volume = nVol; + } + + return s; + + }; + + /** + * Mutes the sound. + * + * @return {SMSound} The SMSound object + */ + + this.mute = function() { + + s.muted = true; + + if (!s.isHTML5) { + flash._setVolume(s.id, 0); + } else if (s._a) { + s._a.muted = true; + } + + return s; + + }; + + /** + * Unmutes the sound. + * + * @return {SMSound} The SMSound object + */ + + this.unmute = function() { + + s.muted = false; + var hasIO = (s._iO.volume !== _undefined); + + if (!s.isHTML5) { + flash._setVolume(s.id, hasIO ? s._iO.volume : s.options.volume); + } else if (s._a) { + s._a.muted = false; + } + + return s; + + }; + + /** + * Toggles the muted state of a sound. + * + * @return {SMSound} The SMSound object + */ + + this.toggleMute = function() { + + return (s.muted ? s.unmute() : s.mute()); + + }; + + /** + * Registers a callback to be fired when a sound reaches a given position during playback. + * + * @param {number} nPosition The position to watch for + * @param {function} oMethod The relevant callback to fire + * @param {object} oScope Optional: The scope to apply the callback to + * @return {SMSound} The SMSound object + */ + + this.onPosition = function(nPosition, oMethod, oScope) { + + // TODO: basic dupe checking? + + onPositionItems.push({ + position: parseInt(nPosition, 10), + method: oMethod, + scope: (oScope !== _undefined ? oScope : s), + fired: false + }); + + return s; + + }; + + // legacy/backwards-compability: lower-case method name + this.onposition = this.onPosition; + + /** + * Removes registered callback(s) from a sound, by position and/or callback. + * + * @param {number} nPosition The position to clear callback(s) for + * @param {function} oMethod Optional: Identify one callback to be removed when multiple listeners exist for one position + * @return {SMSound} The SMSound object + */ + + this.clearOnPosition = function(nPosition, oMethod) { + + var i; + + nPosition = parseInt(nPosition, 10); + + if (isNaN(nPosition)) { + // safety check + return; + } + + for (i = 0; i < onPositionItems.length; i++) { + + if (nPosition === onPositionItems[i].position) { + // remove this item if no method was specified, or, if the method matches + + if (!oMethod || (oMethod === onPositionItems[i].method)) { + + if (onPositionItems[i].fired) { + // decrement "fired" counter, too + onPositionFired--; + } + + onPositionItems.splice(i, 1); + + } + + } + + } + + }; + + this._processOnPosition = function() { + + var i, item, j = onPositionItems.length; + + if (!j || !s.playState || onPositionFired >= j) return false; + + for (i = j - 1; i >= 0; i--) { + + item = onPositionItems[i]; + + if (!item.fired && s.position >= item.position) { + + item.fired = true; + onPositionFired++; + item.method.apply(item.scope, [item.position]); + + // reset j -- onPositionItems.length can be changed in the item callback above... occasionally breaking the loop. + j = onPositionItems.length; + + } + + } + + return true; + + }; + + this._resetOnPosition = function(nPosition) { + + // reset "fired" for items interested in this position + var i, item, j = onPositionItems.length; + + if (!j) return false; + + for (i = j - 1; i >= 0; i--) { + + item = onPositionItems[i]; + + if (item.fired && nPosition <= item.position) { + item.fired = false; + onPositionFired--; + } + + } + + return true; + + }; + + /** + * SMSound() private internals + * -------------------------------- + */ + + applyFromTo = function() { + + var instanceOptions = s._iO, + f = instanceOptions.from, + t = instanceOptions.to, + start, end; + + end = function() { + + // end has been reached. + sm2._wD(s.id + ': "To" time of ' + t + ' reached.'); + + // detach listener + s.clearOnPosition(t, end); + + // stop should clear this, too + s.stop(); + + }; + + start = function() { + + sm2._wD(s.id + ': Playing "from" ' + f); + + // add listener for end + if (t !== null && !isNaN(t)) { + s.onPosition(t, end); + } + + }; + + if (f !== null && !isNaN(f)) { + + // apply to instance options, guaranteeing correct start position. + instanceOptions.position = f; + + // multiShot timing can't be tracked, so prevent that. + instanceOptions.multiShot = false; + + start(); + + } + + // return updated instanceOptions including starting position + return instanceOptions; + + }; + + attachOnPosition = function() { + + var item, + op = s._iO.onposition; + + // attach onposition things, if any, now. + + if (op) { + + for (item in op) { + if (op.hasOwnProperty(item)) { + s.onPosition(parseInt(item, 10), op[item]); + } + } + + } + + }; + + detachOnPosition = function() { + + var item, + op = s._iO.onposition; + + // detach any onposition()-style listeners. + + if (op) { + + for (item in op) { + if (op.hasOwnProperty(item)) { + s.clearOnPosition(parseInt(item, 10)); + } + } + + } + + }; + + start_html5_timer = function() { + + if (s.isHTML5) { + startTimer(s); + } + + }; + + stop_html5_timer = function() { + + if (s.isHTML5) { + stopTimer(s); + } + + }; + + resetProperties = function(retainPosition) { + + if (!retainPosition) { + onPositionItems = []; + onPositionFired = 0; + } + + onplay_called = false; + + s._hasTimer = null; + s._a = null; + s._html5_canplay = false; + s.bytesLoaded = null; + s.bytesTotal = null; + s.duration = (s._iO && s._iO.duration ? s._iO.duration : null); + s.durationEstimate = null; + s.buffered = []; + + // legacy: 1D array + s.eqData = []; + + s.eqData.left = []; + s.eqData.right = []; + + s.failures = 0; + s.isBuffering = false; + s.instanceOptions = {}; + s.instanceCount = 0; + s.loaded = false; + s.metadata = {}; + + // 0 = uninitialised, 1 = loading, 2 = failed/error, 3 = loaded/success + s.readyState = 0; + + s.muted = false; + s.paused = false; + + s.peakData = { + left: 0, + right: 0 + }; + + s.waveformData = { + left: [], + right: [] + }; + + s.playState = 0; + s.position = null; + + s.id3 = {}; + + }; + + resetProperties(); + + /** + * Pseudo-private SMSound internals + * -------------------------------- + */ + + this._onTimer = function(bForce) { + + /** + * HTML5-only _whileplaying() etc. + * called from both HTML5 native events, and polling/interval-based timers + * mimics flash and fires only when time/duration change, so as to be polling-friendly + */ + + var duration, isNew = false, time, x = {}; + + if (s._hasTimer || bForce) { + + // TODO: May not need to track readyState (1 = loading) + + if (s._a && (bForce || ((s.playState > 0 || s.readyState === 1) && !s.paused))) { + + duration = s._get_html5_duration(); + + if (duration !== lastHTML5State.duration) { + + lastHTML5State.duration = duration; + s.duration = duration; + isNew = true; + + } + + // TODO: investigate why this goes wack if not set/re-set each time. + s.durationEstimate = s.duration; + + time = (s._a.currentTime * msecScale || 0); + + if (time !== lastHTML5State.time) { + + lastHTML5State.time = time; + isNew = true; + + } + + if (isNew || bForce) { + + s._whileplaying(time, x, x, x, x); + + } + + }/* else { + + // sm2._wD('_onTimer: Warn for "'+s.id+'": '+(!s._a?'Could not find element. ':'')+(s.playState === 0?'playState bad, 0?':'playState = '+s.playState+', OK')); + + return false; + + }*/ + + } + + return isNew; + + }; + + this._get_html5_duration = function() { + + var instanceOptions = s._iO, + // if audio object exists, use its duration - else, instance option duration (if provided - it's a hack, really, and should be retired) OR null + d = (s._a && s._a.duration ? s._a.duration * msecScale : (instanceOptions && instanceOptions.duration ? instanceOptions.duration : null)), + result = (d && !isNaN(d) && d !== Infinity ? d : null); + + return result; + + }; + + this._apply_loop = function(a, nLoops) { + + /** + * boolean instead of "loop", for webkit? - spec says string. http://www.w3.org/TR/html-markup/audio.html#audio.attrs.loop + * note that loop is either off or infinite under HTML5, unlike Flash which allows arbitrary loop counts to be specified. + */ + + // + if (!a.loop && nLoops > 1) { + sm2._wD('Note: Native HTML5 looping is infinite.', 1); + } + // + + a.loop = (nLoops > 1 ? 'loop' : ''); + + }; + + this._setup_html5 = function(options) { + + var instanceOptions = mixin(s._iO, options), + a = useGlobalHTML5Audio ? globalHTML5Audio : s._a, + dURL = decodeURI(instanceOptions.url), + sameURL; + + /** + * "First things first, I, Poppa..." (reset the previous state of the old sound, if playing) + * Fixes case with devices that can only play one sound at a time + * Otherwise, other sounds in mid-play will be terminated without warning and in a stuck state + */ + + if (useGlobalHTML5Audio) { + + if (dURL === decodeURI(lastGlobalHTML5URL)) { + // global HTML5 audio: re-use of URL + sameURL = true; + } + + } else if (dURL === decodeURI(lastURL)) { + + // options URL is the same as the "last" URL, and we used (loaded) it + sameURL = true; + + } + + if (a) { + + if (a._s) { + + if (useGlobalHTML5Audio) { + + if (a._s && a._s.playState && !sameURL) { + + // global HTML5 audio case, and loading a new URL. stop the currently-playing one. + a._s.stop(); + + } + + } else if (!useGlobalHTML5Audio && dURL === decodeURI(lastURL)) { + + // non-global HTML5 reuse case: same url, ignore request + s._apply_loop(a, instanceOptions.loops); + + return a; + + } + + } + + if (!sameURL) { + + // don't retain onPosition() stuff with new URLs. + + if (lastURL) { + resetProperties(false); + } + + // assign new HTML5 URL + + a.src = instanceOptions.url; + + s.url = instanceOptions.url; + + lastURL = instanceOptions.url; + + lastGlobalHTML5URL = instanceOptions.url; + + a._called_load = false; + + } + + } else { + + if (instanceOptions.autoLoad || instanceOptions.autoPlay) { + + s._a = new Audio(instanceOptions.url); + s._a.load(); + + } else { + + // null for stupid Opera 9.64 case + s._a = (isOpera && opera.version() < 10 ? new Audio(null) : new Audio()); + + } + + // assign local reference + a = s._a; + + a._called_load = false; + + if (useGlobalHTML5Audio) { + + globalHTML5Audio = a; + + } + + } + + s.isHTML5 = true; + + // store a ref on the track + s._a = a; + + // store a ref on the audio + a._s = s; + + add_html5_events(); + + s._apply_loop(a, instanceOptions.loops); + + if (instanceOptions.autoLoad || instanceOptions.autoPlay) { + + s.load(); + + } else { + + // early HTML5 implementation (non-standard) + a.autobuffer = false; + + // standard ('none' is also an option.) + a.preload = 'auto'; + + } + + return a; + + }; + + add_html5_events = function() { + + if (s._a._added_events) return false; + + var f; + + function add(oEvt, oFn, bCapture) { + return s._a ? s._a.addEventListener(oEvt, oFn, bCapture || false) : null; + } + + s._a._added_events = true; + + for (f in html5_events) { + if (html5_events.hasOwnProperty(f)) { + add(f, html5_events[f]); + } + } + + return true; + + }; + + remove_html5_events = function() { + + // Remove event listeners + + var f; + + function remove(oEvt, oFn, bCapture) { + return (s._a ? s._a.removeEventListener(oEvt, oFn, bCapture || false) : null); + } + + sm2._wD(s.id + ': Removing event listeners'); + s._a._added_events = false; + + for (f in html5_events) { + if (html5_events.hasOwnProperty(f)) { + remove(f, html5_events[f]); + } + } + + }; + + /** + * Pseudo-private event internals + * ------------------------------ + */ + + this._onload = function(nSuccess) { + + var fN, + // check for duration to prevent false positives from flash 8 when loading from cache. + loadOK = !!nSuccess || (!s.isHTML5 && fV === 8 && s.duration); + + // + fN = s.id + ': '; + sm2._wD(fN + (loadOK ? 'onload()' : 'Failed to load / invalid sound?' + (!s.duration ? ' Zero-length duration reported.' : ' -') + ' (' + s.url + ')'), (loadOK ? 1 : 2)); + + if (!loadOK && !s.isHTML5) { + if (sm2.sandbox.noRemote === true) { + sm2._wD(fN + str('noNet'), 1); + } + if (sm2.sandbox.noLocal === true) { + sm2._wD(fN + str('noLocal'), 1); + } + } + // + + s.loaded = loadOK; + s.readyState = (loadOK ? 3 : 2); + s._onbufferchange(0); + + if (!loadOK && !s.isHTML5) { + // note: no error code from Flash. + s._onerror(); + } + + if (s._iO.onload) { + wrapCallback(s, function() { + s._iO.onload.apply(s, [loadOK]); + }); + } + + return true; + + }; + + this._onerror = function(errorCode, description) { + + // https://html.spec.whatwg.org/multipage/embedded-content.html#error-codes + if (s._iO.onerror) { + wrapCallback(s, function() { + s._iO.onerror.apply(s, [errorCode, description]); + }); + } + + }; + + this._onbufferchange = function(nIsBuffering) { + + // ignore if not playing + if (s.playState === 0) return false; + + if ((nIsBuffering && s.isBuffering) || (!nIsBuffering && !s.isBuffering)) return false; + + s.isBuffering = (nIsBuffering === 1); + + if (s._iO.onbufferchange) { + sm2._wD(s.id + ': Buffer state change: ' + nIsBuffering); + s._iO.onbufferchange.apply(s, [nIsBuffering]); + } + + return true; + + }; + + /** + * Playback may have stopped due to buffering, or related reason. + * This state can be encountered on iOS < 6 when auto-play is blocked. + */ + + this._onsuspend = function() { + + if (s._iO.onsuspend) { + sm2._wD(s.id + ': Playback suspended'); + s._iO.onsuspend.apply(s); + } + + return true; + + }; + + /** + * flash 9/movieStar + RTMP-only method, should fire only once at most + * at this point we just recreate failed sounds rather than trying to reconnect + */ + + this._onfailure = function(msg, level, code) { + + s.failures++; + sm2._wD(s.id + ': Failure (' + s.failures + '): ' + msg); + + if (s._iO.onfailure && s.failures === 1) { + s._iO.onfailure(msg, level, code); + } else { + sm2._wD(s.id + ': Ignoring failure'); + } + + }; + + /** + * flash 9/movieStar + RTMP-only method for unhandled warnings/exceptions from Flash + * e.g., RTMP "method missing" warning (non-fatal) for getStreamLength on server + */ + + this._onwarning = function(msg, level, code) { + + if (s._iO.onwarning) { + s._iO.onwarning(msg, level, code); + } + + }; + + this._onfinish = function() { + + // store local copy before it gets trashed... + var io_onfinish = s._iO.onfinish; + + s._onbufferchange(0); + s._resetOnPosition(0); + + // reset some state items + if (s.instanceCount) { + + s.instanceCount--; + + if (!s.instanceCount) { + + // remove onPosition listeners, if any + detachOnPosition(); + + // reset instance options + s.playState = 0; + s.paused = false; + s.instanceCount = 0; + s.instanceOptions = {}; + s._iO = {}; + stop_html5_timer(); + + // reset position, too + if (s.isHTML5) { + s.position = 0; + } + + } + + if (!s.instanceCount || s._iO.multiShotEvents) { + // fire onfinish for last, or every instance + if (io_onfinish) { + sm2._wD(s.id + ': onfinish()'); + wrapCallback(s, function() { + io_onfinish.apply(s); + }); + } + } + + } + + }; + + this._whileloading = function(nBytesLoaded, nBytesTotal, nDuration, nBufferLength) { + + var instanceOptions = s._iO; + + s.bytesLoaded = nBytesLoaded; + s.bytesTotal = nBytesTotal; + s.duration = Math.floor(nDuration); + s.bufferLength = nBufferLength; + + if (!s.isHTML5 && !instanceOptions.isMovieStar) { + + if (instanceOptions.duration) { + // use duration from options, if specified and larger. nobody should be specifying duration in options, actually, and it should be retired. + s.durationEstimate = (s.duration > instanceOptions.duration) ? s.duration : instanceOptions.duration; + } else { + s.durationEstimate = parseInt((s.bytesTotal / s.bytesLoaded) * s.duration, 10); + } + + } else { + + s.durationEstimate = s.duration; + + } + + // for flash, reflect sequential-load-style buffering + if (!s.isHTML5) { + s.buffered = [{ + start: 0, + end: s.duration + }]; + } + + // allow whileloading to fire even if "load" fired under HTML5, due to HTTP range/partials + if ((s.readyState !== 3 || s.isHTML5) && instanceOptions.whileloading) { + instanceOptions.whileloading.apply(s); + } + + }; + + this._whileplaying = function(nPosition, oPeakData, oWaveformDataLeft, oWaveformDataRight, oEQData) { + + var instanceOptions = s._iO, + eqLeft; + + // flash safety net + if (isNaN(nPosition) || nPosition === null) return false; + + // Safari HTML5 play() may return small -ve values when starting from position: 0, eg. -50.120396875. Unexpected/invalid per W3, I think. Normalize to 0. + s.position = Math.max(0, nPosition); + + s._processOnPosition(); + + if (!s.isHTML5 && fV > 8) { + + if (instanceOptions.usePeakData && oPeakData !== _undefined && oPeakData) { + s.peakData = { + left: oPeakData.leftPeak, + right: oPeakData.rightPeak + }; + } + + if (instanceOptions.useWaveformData && oWaveformDataLeft !== _undefined && oWaveformDataLeft) { + s.waveformData = { + left: oWaveformDataLeft.split(','), + right: oWaveformDataRight.split(',') + }; + } + + if (instanceOptions.useEQData) { + if (oEQData !== _undefined && oEQData && oEQData.leftEQ) { + eqLeft = oEQData.leftEQ.split(','); + s.eqData = eqLeft; + s.eqData.left = eqLeft; + if (oEQData.rightEQ !== _undefined && oEQData.rightEQ) { + s.eqData.right = oEQData.rightEQ.split(','); + } + } + } + + } + + if (s.playState === 1) { + + // special case/hack: ensure buffering is false if loading from cache (and not yet started) + if (!s.isHTML5 && fV === 8 && !s.position && s.isBuffering) { + s._onbufferchange(0); + } + + if (instanceOptions.whileplaying) { + // flash may call after actual finish + instanceOptions.whileplaying.apply(s); + } + + } + + return true; + + }; + + this._oncaptiondata = function(oData) { + + /** + * internal: flash 9 + NetStream (MovieStar/RTMP-only) feature + * + * @param {object} oData + */ + + sm2._wD(s.id + ': Caption data received.'); + + s.captiondata = oData; + + if (s._iO.oncaptiondata) { + s._iO.oncaptiondata.apply(s, [oData]); + } + + }; + + this._onmetadata = function(oMDProps, oMDData) { + + /** + * internal: flash 9 + NetStream (MovieStar/RTMP-only) feature + * RTMP may include song title, MovieStar content may include encoding info + * + * @param {array} oMDProps (names) + * @param {array} oMDData (values) + */ + + sm2._wD(s.id + ': Metadata received.'); + + var oData = {}, i, j; + + for (i = 0, j = oMDProps.length; i < j; i++) { + oData[oMDProps[i]] = oMDData[i]; + } + + s.metadata = oData; + + if (s._iO.onmetadata) { + s._iO.onmetadata.call(s, s.metadata); + } + + }; + + this._onid3 = function(oID3Props, oID3Data) { + + /** + * internal: flash 8 + flash 9 ID3 feature + * may include artist, song title etc. + * + * @param {array} oID3Props (names) + * @param {array} oID3Data (values) + */ + + sm2._wD(s.id + ': ID3 data received.'); + + var oData = [], i, j; + + for (i = 0, j = oID3Props.length; i < j; i++) { + oData[oID3Props[i]] = oID3Data[i]; + } + + s.id3 = mixin(s.id3, oData); + + if (s._iO.onid3) { + s._iO.onid3.apply(s); + } + + }; + + // flash/RTMP-only + + this._onconnect = function(bSuccess) { + + bSuccess = (bSuccess === 1); + sm2._wD(s.id + ': ' + (bSuccess ? 'Connected.' : 'Failed to connect? - ' + s.url), (bSuccess ? 1 : 2)); + s.connected = bSuccess; + + if (bSuccess) { + + s.failures = 0; + + if (idCheck(s.id)) { + if (s.getAutoPlay()) { + // only update the play state if auto playing + s.play(_undefined, s.getAutoPlay()); + } else if (s._iO.autoLoad) { + s.load(); + } + } + + if (s._iO.onconnect) { + s._iO.onconnect.apply(s, [bSuccess]); + } + + } + + }; + + this._ondataerror = function(sError) { + + // flash 9 wave/eq data handler + // hack: called at start, and end from flash at/after onfinish() + if (s.playState > 0) { + sm2._wD(s.id + ': Data error: ' + sError); + if (s._iO.ondataerror) { + s._iO.ondataerror.apply(s); + } + } + + }; + + // + this._debug(); + // + + }; // SMSound() + + /** + * Private SoundManager internals + * ------------------------------ + */ + + getDocument = function() { + + return (doc.body || doc.getElementsByTagName('div')[0]); + + }; + + id = function(sID) { + + return doc.getElementById(sID); + + }; + + mixin = function(oMain, oAdd) { + + // non-destructive merge + var o1 = (oMain || {}), o2, o; + + // if unspecified, o2 is the default options object + o2 = (oAdd === _undefined ? sm2.defaultOptions : oAdd); + + for (o in o2) { + + if (o2.hasOwnProperty(o) && o1[o] === _undefined) { + + if (typeof o2[o] !== 'object' || o2[o] === null) { + + // assign directly + o1[o] = o2[o]; + + } else { + + // recurse through o2 + o1[o] = mixin(o1[o], o2[o]); + + } + + } + + } + + return o1; + + }; + + wrapCallback = function(oSound, callback) { + + /** + * 03/03/2013: Fix for Flash Player 11.6.602.171 + Flash 8 (flashVersion = 8) SWF issue + * setTimeout() fix for certain SMSound callbacks like onload() and onfinish(), where subsequent calls like play() and load() fail when Flash Player 11.6.602.171 is installed, and using soundManager with flashVersion = 8 (which is the default). + * Not sure of exact cause. Suspect race condition and/or invalid (NaN-style) position argument trickling down to the next JS -> Flash _start() call, in the play() case. + * Fix: setTimeout() to yield, plus safer null / NaN checking on position argument provided to Flash. + * https://getsatisfaction.com/schillmania/topics/recent_chrome_update_seems_to_have_broken_my_sm2_audio_player + */ + if (!oSound.isHTML5 && fV === 8) { + window.setTimeout(callback, 0); + } else { + callback(); + } + + }; + + // additional soundManager properties that soundManager.setup() will accept + + extraOptions = { + onready: 1, + ontimeout: 1, + defaultOptions: 1, + flash9Options: 1, + movieStarOptions: 1 + }; + + assign = function(o, oParent) { + + /** + * recursive assignment of properties, soundManager.setup() helper + * allows property assignment based on whitelist + */ + + var i, + result = true, + hasParent = (oParent !== _undefined), + setupOptions = sm2.setupOptions, + bonusOptions = extraOptions; + + // + + // if soundManager.setup() called, show accepted parameters. + + if (o === _undefined) { + + result = []; + + for (i in setupOptions) { + + if (setupOptions.hasOwnProperty(i)) { + result.push(i); + } + + } + + for (i in bonusOptions) { + + if (bonusOptions.hasOwnProperty(i)) { + + if (typeof sm2[i] === 'object') { + result.push(i + ': {...}'); + } else if (sm2[i] instanceof Function) { + result.push(i + ': function() {...}'); + } else { + result.push(i); + } + + } + + } + + sm2._wD(str('setup', result.join(', '))); + + return false; + + } + + // + + for (i in o) { + + if (o.hasOwnProperty(i)) { + + // if not an {object} we want to recurse through... + + if (typeof o[i] !== 'object' || o[i] === null || o[i] instanceof Array || o[i] instanceof RegExp) { + + // check "allowed" options + + if (hasParent && bonusOptions[oParent] !== _undefined) { + + // valid recursive / nested object option, eg., { defaultOptions: { volume: 50 } } + sm2[oParent][i] = o[i]; + + } else if (setupOptions[i] !== _undefined) { + + // special case: assign to setupOptions object, which soundManager property references + sm2.setupOptions[i] = o[i]; + + // assign directly to soundManager, too + sm2[i] = o[i]; + + } else if (bonusOptions[i] === _undefined) { + + // invalid or disallowed parameter. complain. + complain(str((sm2[i] === _undefined ? 'setupUndef' : 'setupError'), i), 2); + + result = false; + + } else if (sm2[i] instanceof Function) { + /** - * Pseudo-private SMSound internals - * -------------------------------- + * valid extraOptions (bonusOptions) parameter. + * is it a method, like onready/ontimeout? call it. + * multiple parameters should be in an array, eg. soundManager.setup({onready: [myHandler, myScope]}); */ - this._onTimer = function(bForce) { - /** - * HTML5-only _whileplaying() etc. - * called from both HTML5 native events, and polling/interval-based timers - * mimics flash and fires only when time/duration change, so as to be polling-friendly - */ - var duration, isNew = false, - time, x = {}; - if(s._hasTimer || bForce) { - // TODO: May not need to track readyState (1 = loading) - if(s._a && (bForce || ((s.playState > 0 || s.readyState === 1) && !s.paused))) { - duration = s._get_html5_duration(); - if(duration !== lastHTML5State.duration) { - lastHTML5State.duration = duration; - s.duration = duration; - isNew = true; - } - // TODO: investigate why this goes wack if not set/re-set each time. - s.durationEstimate = s.duration; - time = (s._a.currentTime * msecScale || 0); - if(time !== lastHTML5State.time) { - lastHTML5State.time = time; - isNew = true; - } - if(isNew || bForce) { - s._whileplaying(time, x, x, x, x); - } - } - /* else { + sm2[i].apply(sm2, (o[i] instanceof Array ? o[i] : [o[i]])); + + } else { + + // good old-fashioned direct assignment + sm2[i] = o[i]; + + } + + } else if (bonusOptions[i] === _undefined) { + + // recursion case, eg., { defaultOptions: { ... } } + + // invalid or disallowed parameter. complain. + complain(str((sm2[i] === _undefined ? 'setupUndef' : 'setupError'), i), 2); + + result = false; + + } else { + + // recurse through object + return assign(o[i], i); + + } + + } + + } + + return result; + + }; + + function preferFlashCheck(kind) { + + // whether flash should play a given type + return (sm2.preferFlash && hasFlash && !sm2.ignoreFlash && (sm2.flash[kind] !== _undefined && sm2.flash[kind])); + + } + + /** + * Internal DOM2-level event helpers + * --------------------------------- + */ + + event = (function() { + + // normalize event methods + var old = (window.attachEvent), + evt = { + add: (old ? 'attachEvent' : 'addEventListener'), + remove: (old ? 'detachEvent' : 'removeEventListener') + }; + + // normalize "on" event prefix, optional capture argument + function getArgs(oArgs) { + + var args = slice.call(oArgs), + len = args.length; + + if (old) { + // prefix + args[1] = 'on' + args[1]; + if (len > 3) { + // no capture + args.pop(); + } + } else if (len === 3) { + args.push(false); + } + + return args; + + } + + function apply(args, sType) { + + // normalize and call the event method, with the proper arguments + var element = args.shift(), + method = [evt[sType]]; + + if (old) { + // old IE can't do apply(). + element[method](args[0], args[1]); + } else { + element[method].apply(element, args); + } + + } + + function add() { + apply(getArgs(arguments), 'add'); + } + + function remove() { + apply(getArgs(arguments), 'remove'); + } + + return { + add: add, + remove: remove + }; + + }()); + + /** + * Internal HTML5 event handling + * ----------------------------- + */ + + function html5_event(oFn) { + + // wrap html5 event handlers so we don't call them on destroyed and/or unloaded sounds + + return function(e) { + + var s = this._s, + result; + + if (!s || !s._a) { + // + if (s && s.id) { + sm2._wD(s.id + ': Ignoring ' + e.type); + } else { + sm2._wD(h5 + 'Ignoring ' + e.type); + } + // + result = null; + } else { + result = oFn.call(this, e); + } + + return result; + + }; + + } + + html5_events = { + + // HTML5 event-name-to-handler map + + abort: html5_event(function() { + + sm2._wD(this._s.id + ': abort'); + + }), + + // enough has loaded to play + + canplay: html5_event(function() { + + var s = this._s, + position1K; + + if (s._html5_canplay) { + // this event has already fired. ignore. + return; + } + + s._html5_canplay = true; + sm2._wD(s.id + ': canplay'); + s._onbufferchange(0); + + // position according to instance options + position1K = (s._iO.position !== _undefined && !isNaN(s._iO.position) ? s._iO.position / msecScale : null); + + // set the position if position was provided before the sound loaded + if (this.currentTime !== position1K) { + sm2._wD(s.id + ': canplay: Setting position to ' + position1K); + try { + this.currentTime = position1K; + } catch(ee) { + sm2._wD(s.id + ': canplay: Setting position of ' + position1K + ' failed: ' + ee.message, 2); + } + } + + // hack for HTML5 from/to case + if (s._iO._oncanplay) { + s._iO._oncanplay(); + } + + }), + + canplaythrough: html5_event(function() { + + var s = this._s; + + if (!s.loaded) { + s._onbufferchange(0); + s._whileloading(s.bytesLoaded, s.bytesTotal, s._get_html5_duration()); + s._onload(true); + } + + }), + + durationchange: html5_event(function() { + + // durationchange may fire at various times, probably the safest way to capture accurate/final duration. + + var s = this._s, + duration; + + duration = s._get_html5_duration(); + + if (!isNaN(duration) && duration !== s.duration) { + + sm2._wD(this._s.id + ': durationchange (' + duration + ')' + (s.duration ? ', previously ' + s.duration : '')); + + s.durationEstimate = s.duration = duration; + + } + + }), + + // TODO: Reserved for potential use + /* + emptied: html5_event(function() { + + sm2._wD(this._s.id + ': emptied'); + + }), + */ + + ended: html5_event(function() { + + var s = this._s; + + sm2._wD(s.id + ': ended'); + + s._onfinish(); + + }), + + error: html5_event(function() { + + var description = (html5ErrorCodes[this.error.code] || null); + sm2._wD(this._s.id + ': HTML5 error, code ' + this.error.code + (description ? ' (' + description + ')' : '')); + this._s._onload(false); + this._s._onerror(this.error.code, description); + + }), + + loadeddata: html5_event(function() { + + var s = this._s; + + sm2._wD(s.id + ': loadeddata'); + + // safari seems to nicely report progress events, eventually totalling 100% + if (!s._loaded && !isSafari) { + s.duration = s._get_html5_duration(); + } + + }), + + loadedmetadata: html5_event(function() { + + sm2._wD(this._s.id + ': loadedmetadata'); + + }), + + loadstart: html5_event(function() { + + sm2._wD(this._s.id + ': loadstart'); + // assume buffering at first + this._s._onbufferchange(1); + + }), + + play: html5_event(function() { + + // sm2._wD(this._s.id + ': play()'); + // once play starts, no buffering + this._s._onbufferchange(0); + + }), + + playing: html5_event(function() { + + sm2._wD(this._s.id + ': playing ' + String.fromCharCode(9835)); + // once play starts, no buffering + this._s._onbufferchange(0); + + }), + + progress: html5_event(function(e) { + + // note: can fire repeatedly after "loaded" event, due to use of HTTP range/partials + + var s = this._s, + i, j, progStr, buffered = 0, + isProgress = (e.type === 'progress'), + ranges = e.target.buffered, + // firefox 3.6 implements e.loaded/total (bytes) + loaded = (e.loaded || 0), + total = (e.total || 1); + + // reset the "buffered" (loaded byte ranges) array + s.buffered = []; + + if (ranges && ranges.length) { + + // if loaded is 0, try TimeRanges implementation as % of load + // https://developer.mozilla.org/en/DOM/TimeRanges + + // re-build "buffered" array + // HTML5 returns seconds. SM2 API uses msec for setPosition() etc., whether Flash or HTML5. + for (i = 0, j = ranges.length; i < j; i++) { + s.buffered.push({ + start: ranges.start(i) * msecScale, + end: ranges.end(i) * msecScale + }); + } + + // use the last value locally + buffered = (ranges.end(0) - ranges.start(0)) * msecScale; + + // linear case, buffer sum; does not account for seeking and HTTP partials / byte ranges + loaded = Math.min(1, buffered / (e.target.duration * msecScale)); + + // + if (isProgress && ranges.length > 1) { + progStr = []; + j = ranges.length; + for (i = 0; i < j; i++) { + progStr.push((e.target.buffered.start(i) * msecScale) + '-' + (e.target.buffered.end(i) * msecScale)); + } + sm2._wD(this._s.id + ': progress, timeRanges: ' + progStr.join(', ')); + } + + if (isProgress && !isNaN(loaded)) { + sm2._wD(this._s.id + ': progress, ' + Math.floor(loaded * 100) + '% loaded'); + } + // + + } + + if (!isNaN(loaded)) { + + // TODO: prevent calls with duplicate values. + s._whileloading(loaded, total, s._get_html5_duration()); + if (loaded && total && loaded === total) { + // in case "onload" doesn't fire (eg. gecko 1.9.2) + html5_events.canplaythrough.call(this, e); + } + + } + + }), + + ratechange: html5_event(function() { + + sm2._wD(this._s.id + ': ratechange'); + + }), + + suspend: html5_event(function(e) { + + // download paused/stopped, may have finished (eg. onload) + var s = this._s; + + sm2._wD(this._s.id + ': suspend'); + html5_events.progress.call(this, e); + s._onsuspend(); + + }), + + stalled: html5_event(function() { + + sm2._wD(this._s.id + ': stalled'); + + }), + + timeupdate: html5_event(function() { + + this._s._onTimer(); + + }), + + waiting: html5_event(function() { + + var s = this._s; + + // see also: seeking + sm2._wD(this._s.id + ': waiting'); + + // playback faster than download rate, etc. + s._onbufferchange(1); + + }) + + }; + + html5OK = function(iO) { + + // playability test based on URL or MIME type + + var result; + + if (!iO || (!iO.type && !iO.url && !iO.serverURL)) { + + // nothing to check + result = false; + + } else if (iO.serverURL || (iO.type && preferFlashCheck(iO.type))) { + + // RTMP, or preferring flash + result = false; + + } else { + + // Use type, if specified. Pass data: URIs to HTML5. If HTML5-only mode, no other options, so just give 'er + result = ((iO.type ? html5CanPlay({ type: iO.type }) : html5CanPlay({ url: iO.url }) || sm2.html5Only || iO.url.match(/data:/i))); + + } + + return result; + + }; + + html5Unload = function(oAudio) { + + /** + * Internal method: Unload media, and cancel any current/pending network requests. + * Firefox can load an empty URL, which allegedly destroys the decoder and stops the download. + * https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox#Stopping_the_download_of_media + * However, Firefox has been seen loading a relative URL from '' and thus requesting the hosting page on unload. + * Other UA behaviour is unclear, so everyone else gets an about:blank-style URL. + */ + + var url; + + if (oAudio) { + + // Firefox and Chrome accept short WAVe data: URIs. Chome dislikes audio/wav, but accepts audio/wav for data: MIME. + // Desktop Safari complains / fails on data: URI, so it gets about:blank. + url = (isSafari ? emptyURL : (sm2.html5.canPlayType('audio/wav') ? emptyWAV : emptyURL)); + + oAudio.src = url; + + // reset some state, too + if (oAudio._called_unload !== _undefined) { + oAudio._called_load = false; + } + + } + + if (useGlobalHTML5Audio) { + + // ensure URL state is trashed, also + lastGlobalHTML5URL = null; + + } + + return url; + + }; + + html5CanPlay = function(o) { + + /** + * Try to find MIME, test and return truthiness + * o = { + * url: '/path/to/an.mp3', + * type: 'audio/mp3' + * } + */ + + if (!sm2.useHTML5Audio || !sm2.hasHTML5) return false; + + var url = (o.url || null), + mime = (o.type || null), + aF = sm2.audioFormats, + result, + offset, + fileExt, + item; + + // account for known cases like audio/mp3 + + if (mime && sm2.html5[mime] !== _undefined) return (sm2.html5[mime] && !preferFlashCheck(mime)); + + if (!html5Ext) { + + html5Ext = []; + + for (item in aF) { + + if (aF.hasOwnProperty(item)) { + + html5Ext.push(item); + + if (aF[item].related) { + html5Ext = html5Ext.concat(aF[item].related); + } + + } + + } + + html5Ext = new RegExp('\\.(' + html5Ext.join('|') + ')(\\?.*)?$', 'i'); + + } + + // TODO: Strip URL queries, etc. + fileExt = (url ? url.toLowerCase().match(html5Ext) : null); + + if (!fileExt || !fileExt.length) { + + if (!mime) { + + result = false; + + } else { + + // audio/mp3 -> mp3, result should be known + offset = mime.indexOf(';'); + + // strip "audio/X; codecs..." + fileExt = (offset !== -1 ? mime.substr(0, offset) : mime).substr(6); + + } + + } else { + + // match the raw extension name - "mp3", for example + fileExt = fileExt[1]; + + } + + if (fileExt && sm2.html5[fileExt] !== _undefined) { + + // result known + result = (sm2.html5[fileExt] && !preferFlashCheck(fileExt)); + + } else { + + mime = 'audio/' + fileExt; + result = sm2.html5.canPlayType({ type: mime }); + + sm2.html5[fileExt] = result; + + // sm2._wD('canPlayType, found result: ' + result); + result = (result && sm2.html5[mime] && !preferFlashCheck(mime)); + } + + return result; + + }; + + testHTML5 = function() { + + /** + * Internal: Iterates over audioFormats, determining support eg. audio/mp3, audio/mpeg and so on + * assigns results to html5[] and flash[]. + */ + + if (!sm2.useHTML5Audio || !sm2.hasHTML5) { + + // without HTML5, we need Flash. + sm2.html5.usingFlash = true; + needsFlash = true; + + return false; + + } + + // double-whammy: Opera 9.64 throws WRONG_ARGUMENTS_ERR if no parameter passed to Audio(), and Webkit + iOS happily tries to load "null" as a URL. :/ + var a = (Audio !== _undefined ? (isOpera && opera.version() < 10 ? new Audio(null) : new Audio()) : null), + item, lookup, support = {}, aF, i; + + function cp(m) { + + var canPlay, j, + result = false, + isOK = false; + + if (!a || typeof a.canPlayType !== 'function') return result; + + if (m instanceof Array) { + + // iterate through all mime types, return any successes + + for (i = 0, j = m.length; i < j; i++) { + + if (sm2.html5[m[i]] || a.canPlayType(m[i]).match(sm2.html5Test)) { + + isOK = true; + sm2.html5[m[i]] = true; + + // note flash support, too + sm2.flash[m[i]] = !!(m[i].match(flashMIME)); + + } + + } + + result = isOK; + + } else { + + canPlay = (a && typeof a.canPlayType === 'function' ? a.canPlayType(m) : false); + result = !!(canPlay && (canPlay.match(sm2.html5Test))); + + } + + return result; + + } + + // test all registered formats + codecs + + aF = sm2.audioFormats; + + for (item in aF) { + + if (aF.hasOwnProperty(item)) { + + lookup = 'audio/' + item; + + support[item] = cp(aF[item].type); + + // write back generic type too, eg. audio/mp3 + support[lookup] = support[item]; + + // assign flash + if (item.match(flashMIME)) { + + sm2.flash[item] = true; + sm2.flash[lookup] = true; + + } else { + + sm2.flash[item] = false; + sm2.flash[lookup] = false; + + } + + // assign result to related formats, too + + if (aF[item] && aF[item].related) { + + for (i = aF[item].related.length - 1; i >= 0; i--) { + + // eg. audio/m4a + support['audio/' + aF[item].related[i]] = support[item]; + sm2.html5[aF[item].related[i]] = support[item]; + sm2.flash[aF[item].related[i]] = support[item]; + + } + + } + + } + + } + + support.canPlayType = (a ? cp : null); + sm2.html5 = mixin(sm2.html5, support); + + sm2.html5.usingFlash = featureCheck(); + needsFlash = sm2.html5.usingFlash; + + return true; + + }; + + strings = { + + // + notReady: 'Unavailable - wait until onready() has fired.', + notOK: 'Audio support is not available.', + domError: sm + 'exception caught while appending SWF to DOM.', + spcWmode: 'Removing wmode, preventing known SWF loading issue(s)', + swf404: smc + 'Verify that %s is a valid path.', + tryDebug: 'Try ' + sm + '.debugFlash = true for more security details (output goes to SWF.)', + checkSWF: 'See SWF output for more debug info.', + localFail: smc + 'Non-HTTP page (' + doc.location.protocol + ' URL?) Review Flash player security settings for this special case:\nhttp://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html\nMay need to add/allow path, eg. c:/sm2/ or /users/me/sm2/', + waitFocus: smc + 'Special case: Waiting for SWF to load with window focus...', + waitForever: smc + 'Waiting indefinitely for Flash (will recover if unblocked)...', + waitSWF: smc + 'Waiting for 100% SWF load...', + needFunction: smc + 'Function object expected for %s', + badID: 'Sound ID "%s" should be a string, starting with a non-numeric character', + currentObj: smc + '_debug(): Current sound objects', + waitOnload: smc + 'Waiting for window.onload()', + docLoaded: smc + 'Document already loaded', + onload: smc + 'initComplete(): calling soundManager.onload()', + onloadOK: sm + '.onload() complete', + didInit: smc + 'init(): Already called?', + secNote: 'Flash security note: Network/internet URLs will not load due to security restrictions. Access can be configured via Flash Player Global Security Settings Page: http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html', + badRemove: smc + 'Failed to remove Flash node.', + shutdown: sm + '.disable(): Shutting down', + queue: smc + 'Queueing %s handler', + smError: 'SMSound.load(): Exception: JS-Flash communication failed, or JS error.', + fbTimeout: 'No flash response, applying .' + swfCSS.swfTimedout + ' CSS...', + fbLoaded: 'Flash loaded', + fbHandler: smc + 'flashBlockHandler()', + manURL: 'SMSound.load(): Using manually-assigned URL', + onURL: sm + '.load(): current URL already assigned.', + badFV: sm + '.flashVersion must be 8 or 9. "%s" is invalid. Reverting to %s.', + as2loop: 'Note: Setting stream:false so looping can work (flash 8 limitation)', + noNSLoop: 'Note: Looping not implemented for MovieStar formats', + needfl9: 'Note: Switching to flash 9, required for MP4 formats.', + mfTimeout: 'Setting flashLoadTimeout = 0 (infinite) for off-screen, mobile flash case', + needFlash: smc + 'Fatal error: Flash is needed to play some required formats, but is not available.', + gotFocus: smc + 'Got window focus.', + policy: 'Enabling usePolicyFile for data access', + setup: sm + '.setup(): allowed parameters: %s', + setupError: sm + '.setup(): "%s" cannot be assigned with this method.', + setupUndef: sm + '.setup(): Could not find option "%s"', + setupLate: sm + '.setup(): url, flashVersion and html5Test property changes will not take effect until reboot().', + noURL: smc + 'Flash URL required. Call soundManager.setup({url:...}) to get started.', + sm2Loaded: 'SoundManager 2: Ready. ' + String.fromCharCode(10003), + reset: sm + '.reset(): Removing event callbacks', + mobileUA: 'Mobile UA detected, preferring HTML5 by default.', + globalHTML5: 'Using singleton HTML5 Audio() pattern for this device.', + ignoreMobile: 'Ignoring mobile restrictions for this device.' + // + + }; + + str = function() { + + // internal string replace helper. + // arguments: o [,items to replace] + // + + var args, + i, j, o, + sstr; + + // real array, please + args = slice.call(arguments); + + // first argument + o = args.shift(); + + sstr = (strings && strings[o] ? strings[o] : ''); + + if (sstr && args && args.length) { + for (i = 0, j = args.length; i < j; i++) { + sstr = sstr.replace('%s', args[i]); + } + } + + return sstr; + // + + }; + + loopFix = function(sOpt) { + + // flash 8 requires stream = false for looping to work + if (fV === 8 && sOpt.loops > 1 && sOpt.stream) { + _wDS('as2loop'); + sOpt.stream = false; + } + + return sOpt; + + }; + + policyFix = function(sOpt, sPre) { + + if (sOpt && !sOpt.usePolicyFile && (sOpt.onid3 || sOpt.usePeakData || sOpt.useWaveformData || sOpt.useEQData)) { + sm2._wD((sPre || '') + str('policy')); + sOpt.usePolicyFile = true; + } + + return sOpt; + + }; + + complain = function(sMsg) { + + // + if (hasConsole && console.warn !== _undefined) { + console.warn(sMsg); + } else { + sm2._wD(sMsg); + } + // + + }; + + doNothing = function() { + + return false; + + }; + + disableObject = function(o) { + + var oProp; + + for (oProp in o) { + if (o.hasOwnProperty(oProp) && typeof o[oProp] === 'function') { + o[oProp] = doNothing; + } + } + + oProp = null; + + }; + + failSafely = function(bNoDisable) { + + // general failure exception handler + + if (bNoDisable === _undefined) { + bNoDisable = false; + } + + if (disabled || bNoDisable) { + sm2.disable(bNoDisable); + } + + }; + + normalizeMovieURL = function(movieURL) { + + var urlParams = null, url; + + if (movieURL) { + + if (movieURL.match(/\.swf(\?.*)?$/i)) { + + urlParams = movieURL.substr(movieURL.toLowerCase().lastIndexOf('.swf?') + 4); + + // assume user knows what they're doing + if (urlParams) return movieURL; + + } else if (movieURL.lastIndexOf('/') !== movieURL.length - 1) { + + // append trailing slash, if needed + movieURL += '/'; + + } + + } + + url = (movieURL && movieURL.lastIndexOf('/') !== -1 ? movieURL.substr(0, movieURL.lastIndexOf('/') + 1) : './') + sm2.movieURL; + + if (sm2.noSWFCache) { + url += ('?ts=' + new Date().getTime()); + } + + return url; + + }; + + setVersionInfo = function() { + + // short-hand for internal use + + fV = parseInt(sm2.flashVersion, 10); + + if (fV !== 8 && fV !== 9) { + sm2._wD(str('badFV', fV, defaultFlashVersion)); + sm2.flashVersion = fV = defaultFlashVersion; + } + + // debug flash movie, if applicable + + var isDebug = (sm2.debugMode || sm2.debugFlash ? '_debug.swf' : '.swf'); + + if (sm2.useHTML5Audio && !sm2.html5Only && sm2.audioFormats.mp4.required && fV < 9) { + sm2._wD(str('needfl9')); + sm2.flashVersion = fV = 9; + } + + sm2.version = sm2.versionNumber + (sm2.html5Only ? ' (HTML5-only mode)' : (fV === 9 ? ' (AS3/Flash 9)' : ' (AS2/Flash 8)')); + + // set up default options + if (fV > 8) { + + // +flash 9 base options + sm2.defaultOptions = mixin(sm2.defaultOptions, sm2.flash9Options); + sm2.features.buffering = true; + + // +moviestar support + sm2.defaultOptions = mixin(sm2.defaultOptions, sm2.movieStarOptions); + sm2.filePatterns.flash9 = new RegExp('\\.(mp3|' + netStreamTypes.join('|') + ')(\\?.*)?$', 'i'); + sm2.features.movieStar = true; + + } else { + + sm2.features.movieStar = false; + + } + + // regExp for flash canPlay(), etc. + sm2.filePattern = sm2.filePatterns[(fV !== 8 ? 'flash9' : 'flash8')]; + + // if applicable, use _debug versions of SWFs + sm2.movieURL = (fV === 8 ? 'soundmanager2.swf' : 'soundmanager2_flash9.swf').replace('.swf', isDebug); + + sm2.features.peakData = sm2.features.waveformData = sm2.features.eqData = (fV > 8); + + }; + + setPolling = function(bPolling, bHighPerformance) { + + if (!flash) { + return; + } + + flash._setPolling(bPolling, bHighPerformance); + + }; + + initDebug = function() { + + // starts debug mode, creating output
for UAs without console object + + // allow force of debug mode via URL + // + if (sm2.debugURLParam.test(wl)) { + sm2.setupOptions.debugMode = sm2.debugMode = true; + } + + if (id(sm2.debugID)) { + return; + } + + var oD, oDebug, oTarget, oToggle, tmp; + + if (sm2.debugMode && !id(sm2.debugID) && (!hasConsole || !sm2.useConsole || !sm2.consoleOnly)) { + + oD = doc.createElement('div'); + oD.id = sm2.debugID + '-toggle'; + + oToggle = { + position: 'fixed', + bottom: '0px', + right: '0px', + width: '1.2em', + height: '1.2em', + lineHeight: '1.2em', + margin: '2px', + textAlign: 'center', + border: '1px solid #999', + cursor: 'pointer', + background: '#fff', + color: '#333', + zIndex: 10001 + }; + + oD.appendChild(doc.createTextNode('-')); + oD.onclick = toggleDebug; + oD.title = 'Toggle SM2 debug console'; + + if (ua.match(/msie 6/i)) { + oD.style.position = 'absolute'; + oD.style.cursor = 'hand'; + } + + for (tmp in oToggle) { + if (oToggle.hasOwnProperty(tmp)) { + oD.style[tmp] = oToggle[tmp]; + } + } + + oDebug = doc.createElement('div'); + oDebug.id = sm2.debugID; + oDebug.style.display = (sm2.debugMode ? 'block' : 'none'); + + if (sm2.debugMode && !id(oD.id)) { + try { + oTarget = getDocument(); + oTarget.appendChild(oD); + } catch(e2) { + throw new Error(str('domError') + ' \n' + e2.toString()); + } + oTarget.appendChild(oDebug); + } + + } + + oTarget = null; + // + + }; + + idCheck = this.getSoundById; + + // + _wDS = function(o, errorLevel) { + + return (!o ? '' : sm2._wD(str(o), errorLevel)); + + }; + + toggleDebug = function() { + + var o = id(sm2.debugID), + oT = id(sm2.debugID + '-toggle'); + + if (!o) { + return; + } + + if (debugOpen) { + // minimize + oT.innerHTML = '+'; + o.style.display = 'none'; + } else { + oT.innerHTML = '-'; + o.style.display = 'block'; + } + + debugOpen = !debugOpen; + + }; + + debugTS = function(sEventType, bSuccess, sMessage) { + + // troubleshooter debug hooks + + if (window.sm2Debugger !== _undefined) { + try { + sm2Debugger.handleEvent(sEventType, bSuccess, sMessage); + } catch(e) { + // oh well + return false; + } + } + + return true; + + }; + // + + getSWFCSS = function() { + + var css = []; + + if (sm2.debugMode) { + css.push(swfCSS.sm2Debug); + } + + if (sm2.debugFlash) { + css.push(swfCSS.flashDebug); + } + + if (sm2.useHighPerformance) { + css.push(swfCSS.highPerf); + } + + return css.join(' '); + + }; + + flashBlockHandler = function() { + + // *possible* flash block situation. + + var name = str('fbHandler'), + p = sm2.getMoviePercent(), + css = swfCSS, + error = { + type: 'FLASHBLOCK' + }; + + if (sm2.html5Only) { + // no flash, or unused + return; + } + + if (!sm2.ok()) { + + if (needsFlash) { + // make the movie more visible, so user can fix + sm2.oMC.className = getSWFCSS() + ' ' + css.swfDefault + ' ' + (p === null ? css.swfTimedout : css.swfError); + sm2._wD(name + ': ' + str('fbTimeout') + (p ? ' (' + str('fbLoaded') + ')' : '')); + } + + sm2.didFlashBlock = true; + + // fire onready(), complain lightly + processOnEvents({ + type: 'ontimeout', + ignoreInit: true, + error: error + }); + + catchError(error); + + } else { + + // SM2 loaded OK (or recovered) + + // + if (sm2.didFlashBlock) { + sm2._wD(name + ': Unblocked'); + } + // + + if (sm2.oMC) { + sm2.oMC.className = [getSWFCSS(), css.swfDefault, css.swfLoaded + (sm2.didFlashBlock ? ' ' + css.swfUnblocked : '')].join(' '); + } + + } + + }; + + addOnEvent = function(sType, oMethod, oScope) { + + if (on_queue[sType] === _undefined) { + on_queue[sType] = []; + } + + on_queue[sType].push({ + method: oMethod, + scope: (oScope || null), + fired: false + }); + + }; + + processOnEvents = function(oOptions) { + + // if unspecified, assume OK/error + + if (!oOptions) { + oOptions = { + type: (sm2.ok() ? 'onready' : 'ontimeout') + }; + } + + // not ready yet. + if (!didInit && oOptions && !oOptions.ignoreInit) return false; + + // invalid case + if (oOptions.type === 'ontimeout' && (sm2.ok() || (disabled && !oOptions.ignoreInit))) return false; + + var status = { + success: (oOptions && oOptions.ignoreInit ? sm2.ok() : !disabled) + }, + + // queue specified by type, or none + srcQueue = (oOptions && oOptions.type ? on_queue[oOptions.type] || [] : []), + + queue = [], i, j, + args = [status], + canRetry = (needsFlash && !sm2.ok()); + + if (oOptions.error) { + args[0].error = oOptions.error; + } + + for (i = 0, j = srcQueue.length; i < j; i++) { + if (srcQueue[i].fired !== true) { + queue.push(srcQueue[i]); + } + } + + if (queue.length) { + + // sm2._wD(sm + ': Firing ' + queue.length + ' ' + oOptions.type + '() item' + (queue.length === 1 ? '' : 's')); + for (i = 0, j = queue.length; i < j; i++) { + + if (queue[i].scope) { + queue[i].method.apply(queue[i].scope, args); + } else { + queue[i].method.apply(this, args); + } + + if (!canRetry) { + // useFlashBlock and SWF timeout case doesn't count here. + queue[i].fired = true; + + } + + } + + } + + return true; + + }; + + initUserOnload = function() { + + window.setTimeout(function() { + + if (sm2.useFlashBlock) { + flashBlockHandler(); + } + + processOnEvents(); + + // call user-defined "onload", scoped to window + + if (typeof sm2.onload === 'function') { + _wDS('onload', 1); + sm2.onload.apply(window); + _wDS('onloadOK', 1); + } + + if (sm2.waitForWindowLoad) { + event.add(window, 'load', initUserOnload); + } + + }, 1); + + }; + + detectFlash = function() { + + /** + * Hat tip: Flash Detect library (BSD, (C) 2007) by Carl "DocYes" S. Yestrau + * http://featureblend.com/javascript-flash-detection-library.html / http://featureblend.com/license.txt + */ + + // this work has already been done. + if (hasFlash !== _undefined) return hasFlash; + + var hasPlugin = false, n = navigator, obj, type, types, AX = window.ActiveXObject; + + // MS Edge 14 throws an "Unspecified Error" because n.plugins is inaccessible due to permissions + var nP; + + try { + nP = n.plugins; + } catch(e) { + nP = undefined; + } + + if (nP && nP.length) { + + type = 'application/x-shockwave-flash'; + types = n.mimeTypes; + + if (types && types[type] && types[type].enabledPlugin && types[type].enabledPlugin.description) { + hasPlugin = true; + } + + } else if (AX !== _undefined && !ua.match(/MSAppHost/i)) { + + // Windows 8 Store Apps (MSAppHost) are weird (compatibility?) and won't complain here, but will barf if Flash/ActiveX object is appended to the DOM. + try { + obj = new AX('ShockwaveFlash.ShockwaveFlash'); + } catch(e) { + // oh well + obj = null; + } + + hasPlugin = (!!obj); + + // cleanup, because it is ActiveX after all + obj = null; + + } + + hasFlash = hasPlugin; + + return hasPlugin; - // sm2._wD('_onTimer: Warn for "'+s.id+'": '+(!s._a?'Could not find element. ':'')+(s.playState === 0?'playState bad, 0?':'playState = '+s.playState+', OK')); + }; - return false; + featureCheck = function() { - }*/ - return isNew; - } - }; - this._get_html5_duration = function() { - var instanceOptions = s._iO, - // if audio object exists, use its duration - else, instance option duration (if provided - it's a hack, really, and should be retired) OR null - d = (s._a && s._a.duration ? s._a.duration * msecScale : (instanceOptions && instanceOptions.duration ? instanceOptions.duration : null)), - result = (d && !isNaN(d) && d !== Infinity ? d : null); - return result; - }; - this._apply_loop = function(a, nLoops) { - /** - * boolean instead of "loop", for webkit? - spec says string. http://www.w3.org/TR/html-markup/audio.html#audio.attrs.loop - * note that loop is either off or infinite under HTML5, unlike Flash which allows arbitrary loop counts to be specified. - */ - // - if(!a.loop && nLoops > 1) { - sm2._wD('Note: Native HTML5 looping is infinite.', 1); - } - // - a.loop = (nLoops > 1 ? 'loop' : ''); - }; - this._setup_html5 = function(oOptions) { - var instanceOptions = mixin(s._iO, oOptions), - a = useGlobalHTML5Audio ? globalHTML5Audio : s._a, - dURL = decodeURI(instanceOptions.url), - sameURL; - /** - * "First things first, I, Poppa..." (reset the previous state of the old sound, if playing) - * Fixes case with devices that can only play one sound at a time - * Otherwise, other sounds in mid-play will be terminated without warning and in a stuck state - */ - if(useGlobalHTML5Audio) { - if(dURL === decodeURI(lastGlobalHTML5URL)) { - // global HTML5 audio: re-use of URL - sameURL = true; - } - } else if(dURL === decodeURI(lastURL)) { - // options URL is the same as the "last" URL, and we used (loaded) it - sameURL = true; - } - if(a) { - if(a._s) { - if(useGlobalHTML5Audio) { - if(a._s && a._s.playState && !sameURL) { - // global HTML5 audio case, and loading a new URL. stop the currently-playing one. - a._s.stop(); - } - } else if(!useGlobalHTML5Audio && dURL === decodeURI(lastURL)) { - // non-global HTML5 reuse case: same url, ignore request - s._apply_loop(a, instanceOptions.loops); - return a; - } - } - if(!sameURL) { - // don't retain onPosition() stuff with new URLs. - if(lastURL) { - resetProperties(false); - } - // assign new HTML5 URL - a.src = instanceOptions.url; - s.url = instanceOptions.url; - lastURL = instanceOptions.url; - lastGlobalHTML5URL = instanceOptions.url; - a._called_load = false; - } - } else { - if(instanceOptions.autoLoad || instanceOptions.autoPlay) { - s._a = new Audio(instanceOptions.url); - s._a.load(); - } else { - // null for stupid Opera 9.64 case - s._a = (isOpera && opera.version() < 10 ? new Audio(null) : new Audio()); - } - // assign local reference - a = s._a; - a._called_load = false; - if(useGlobalHTML5Audio) { - globalHTML5Audio = a; - } - } - s.isHTML5 = true; - // store a ref on the track - s._a = a; - // store a ref on the audio - a._s = s; - add_html5_events(); - s._apply_loop(a, instanceOptions.loops); - if(instanceOptions.autoLoad || instanceOptions.autoPlay) { - s.load(); - } else { - // early HTML5 implementation (non-standard) - a.autobuffer = false; - // standard ('none' is also an option.) - a.preload = 'auto'; - } - return a; - }; - add_html5_events = function() { - if(s._a._added_events) { - return false; - } - var f; + var flashNeeded, + item, + formats = sm2.audioFormats, + // iPhone <= 3.1 has broken HTML5 audio(), but firmware 3.2 (original iPad) + iOS4 works. + isSpecial = (is_iDevice && !!(ua.match(/os (1|2|3_0|3_1)\s/i))); - function add(oEvt, oFn, bCapture) { - return s._a ? s._a.addEventListener(oEvt, oFn, bCapture || false) : null; - } - s._a._added_events = true; - for(f in html5_events) { - if(html5_events.hasOwnProperty(f)) { - add(f, html5_events[f]); - } - } - return true; - }; - remove_html5_events = function() { - // Remove event listeners - var f; + if (isSpecial) { - function remove(oEvt, oFn, bCapture) { - return(s._a ? s._a.removeEventListener(oEvt, oFn, bCapture || false) : null); - } - sm2._wD(s.id + ': Removing event listeners'); - s._a._added_events = false; - for(f in html5_events) { - if(html5_events.hasOwnProperty(f)) { - remove(f, html5_events[f]); - } - } - }; - /** - * Pseudo-private event internals - * ------------------------------ - */ - this._onload = function(nSuccess) { - var fN, - // check for duration to prevent false positives from flash 8 when loading from cache. - loadOK = !! nSuccess || (!s.isHTML5 && fV === 8 && s.duration); - // - fN = s.id + ': '; - sm2._wD(fN + (loadOK ? 'onload()' : 'Failed to load / invalid sound?' + (!s.duration ? ' Zero-length duration reported.' : ' -') + ' (' + s.url + ')'), (loadOK ? 1 : 2)); - if(!loadOK && !s.isHTML5) { - if(sm2.sandbox.noRemote === true) { - sm2._wD(fN + str('noNet'), 1); - } - if(sm2.sandbox.noLocal === true) { - sm2._wD(fN + str('noLocal'), 1); - } - } - // - s.loaded = loadOK; - s.readyState = loadOK ? 3 : 2; - s._onbufferchange(0); - if(s._iO.onload) { - wrapCallback(s, function() { - s._iO.onload.apply(s, [loadOK]); - }); - } - return true; - }; - this._onbufferchange = function(nIsBuffering) { - if(s.playState === 0) { - // ignore if not playing - return false; - } - if((nIsBuffering && s.isBuffering) || (!nIsBuffering && !s.isBuffering)) { - return false; - } - s.isBuffering = (nIsBuffering === 1); - if(s._iO.onbufferchange) { - sm2._wD(s.id + ': Buffer state change: ' + nIsBuffering); - s._iO.onbufferchange.apply(s, [nIsBuffering]); - } - return true; - }; - /** - * Playback may have stopped due to buffering, or related reason. - * This state can be encountered on iOS < 6 when auto-play is blocked. - */ - this._onsuspend = function() { - if(s._iO.onsuspend) { - sm2._wD(s.id + ': Playback suspended'); - s._iO.onsuspend.apply(s); - } - return true; - }; - /** - * flash 9/movieStar + RTMP-only method, should fire only once at most - * at this point we just recreate failed sounds rather than trying to reconnect - */ - this._onfailure = function(msg, level, code) { - s.failures++; - sm2._wD(s.id + ': Failure (' + s.failures + '): ' + msg); - if(s._iO.onfailure && s.failures === 1) { - s._iO.onfailure(msg, level, code); - } else { - sm2._wD(s.id + ': Ignoring failure'); - } - }; - /** - * flash 9/movieStar + RTMP-only method for unhandled warnings/exceptions from Flash - * e.g., RTMP "method missing" warning (non-fatal) for getStreamLength on server - */ - this._onwarning = function(msg, level, code) { - if(s._iO.onwarning) { - s._iO.onwarning(msg, level, code); - } - }; - this._onfinish = function() { - // store local copy before it gets trashed... - var io_onfinish = s._iO.onfinish; - s._onbufferchange(0); - s._resetOnPosition(0); - // reset some state items - if(s.instanceCount) { - s.instanceCount--; - if(!s.instanceCount) { - // remove onPosition listeners, if any - detachOnPosition(); - // reset instance options - s.playState = 0; - s.paused = false; - s.instanceCount = 0; - s.instanceOptions = {}; - s._iO = {}; - stop_html5_timer(); - // reset position, too - if(s.isHTML5) { - s.position = 0; - } - } - if(!s.instanceCount || s._iO.multiShotEvents) { - // fire onfinish for last, or every instance - if(io_onfinish) { - sm2._wD(s.id + ': onfinish()'); - wrapCallback(s, function() { - io_onfinish.apply(s); - }); - } - } - } - }; - this._whileloading = function(nBytesLoaded, nBytesTotal, nDuration, nBufferLength) { - var instanceOptions = s._iO; - s.bytesLoaded = nBytesLoaded; - s.bytesTotal = nBytesTotal; - s.duration = Math.floor(nDuration); - s.bufferLength = nBufferLength; - if(!s.isHTML5 && !instanceOptions.isMovieStar) { - if(instanceOptions.duration) { - // use duration from options, if specified and larger. nobody should be specifying duration in options, actually, and it should be retired. - s.durationEstimate = (s.duration > instanceOptions.duration) ? s.duration : instanceOptions.duration; - } else { - s.durationEstimate = parseInt((s.bytesTotal / s.bytesLoaded) * s.duration, 10); - } - } else { - s.durationEstimate = s.duration; - } - // for flash, reflect sequential-load-style buffering - if(!s.isHTML5) { - s.buffered = [{ - 'start': 0, - 'end': s.duration - }]; - } - // allow whileloading to fire even if "load" fired under HTML5, due to HTTP range/partials - if((s.readyState !== 3 || s.isHTML5) && instanceOptions.whileloading) { - instanceOptions.whileloading.apply(s); - } - }; - this._whileplaying = function(nPosition, oPeakData, oWaveformDataLeft, oWaveformDataRight, oEQData) { - var instanceOptions = s._iO, - eqLeft; - if(isNaN(nPosition) || nPosition === null) { - // flash safety net - return false; - } - // Safari HTML5 play() may return small -ve values when starting from position: 0, eg. -50.120396875. Unexpected/invalid per W3, I think. Normalize to 0. - s.position = Math.max(0, nPosition); - s._processOnPosition(); - if(!s.isHTML5 && fV > 8) { - if(instanceOptions.usePeakData && oPeakData !== _undefined && oPeakData) { - s.peakData = { - left: oPeakData.leftPeak, - right: oPeakData.rightPeak - }; - } - if(instanceOptions.useWaveformData && oWaveformDataLeft !== _undefined && oWaveformDataLeft) { - s.waveformData = { - left: oWaveformDataLeft.split(','), - right: oWaveformDataRight.split(',') - }; - } - if(instanceOptions.useEQData) { - if(oEQData !== _undefined && oEQData && oEQData.leftEQ) { - eqLeft = oEQData.leftEQ.split(','); - s.eqData = eqLeft; - s.eqData.left = eqLeft; - if(oEQData.rightEQ !== _undefined && oEQData.rightEQ) { - s.eqData.right = oEQData.rightEQ.split(','); - } - } - } - } - if(s.playState === 1) { - // special case/hack: ensure buffering is false if loading from cache (and not yet started) - if(!s.isHTML5 && fV === 8 && !s.position && s.isBuffering) { - s._onbufferchange(0); - } - if(instanceOptions.whileplaying) { - // flash may call after actual finish - instanceOptions.whileplaying.apply(s); - } - } - return true; - }; - this._oncaptiondata = function(oData) { - /** - * internal: flash 9 + NetStream (MovieStar/RTMP-only) feature - * - * @param {object} oData - */ - sm2._wD(s.id + ': Caption data received.'); - s.captiondata = oData; - if(s._iO.oncaptiondata) { - s._iO.oncaptiondata.apply(s, [oData]); - } - }; - this._onmetadata = function(oMDProps, oMDData) { - /** - * internal: flash 9 + NetStream (MovieStar/RTMP-only) feature - * RTMP may include song title, MovieStar content may include encoding info - * - * @param {array} oMDProps (names) - * @param {array} oMDData (values) - */ - sm2._wD(s.id + ': Metadata received.'); - var oData = {}, i, j; - for(i = 0, j = oMDProps.length; i < j; i++) { - oData[oMDProps[i]] = oMDData[i]; - } - s.metadata = oData; - console.log('updated metadata', s.metadata); - if(s._iO.onmetadata) { - s._iO.onmetadata.call(s, s.metadata); - } - }; - this._onid3 = function(oID3Props, oID3Data) { - /** - * internal: flash 8 + flash 9 ID3 feature - * may include artist, song title etc. - * - * @param {array} oID3Props (names) - * @param {array} oID3Data (values) - */ - sm2._wD(s.id + ': ID3 data received.'); - var oData = [], - i, j; - for(i = 0, j = oID3Props.length; i < j; i++) { - oData[oID3Props[i]] = oID3Data[i]; - } - s.id3 = mixin(s.id3, oData); - if(s._iO.onid3) { - s._iO.onid3.apply(s); - } - }; - // flash/RTMP-only - this._onconnect = function(bSuccess) { - bSuccess = (bSuccess === 1); - sm2._wD(s.id + ': ' + (bSuccess ? 'Connected.' : 'Failed to connect? - ' + s.url), (bSuccess ? 1 : 2)); - s.connected = bSuccess; - if(bSuccess) { - s.failures = 0; - if(idCheck(s.id)) { - if(s.getAutoPlay()) { - // only update the play state if auto playing - s.play(_undefined, s.getAutoPlay()); - } else if(s._iO.autoLoad) { - s.load(); - } - } - if(s._iO.onconnect) { - s._iO.onconnect.apply(s, [bSuccess]); - } - } - }; - this._ondataerror = function(sError) { - // flash 9 wave/eq data handler - // hack: called at start, and end from flash at/after onfinish() - if(s.playState > 0) { - sm2._wD(s.id + ': Data error: ' + sError); - if(s._iO.ondataerror) { - s._iO.ondataerror.apply(s); - } - } - }; - // - this._debug(); - // - }; // SMSound() - /** - * Private SoundManager internals - * ------------------------------ - */ - getDocument = function() { - return(doc.body || doc.getElementsByTagName('div')[0]); - }; - id = function(sID) { - return doc.getElementById(sID); - }; - mixin = function(oMain, oAdd) { - // non-destructive merge - var o1 = (oMain || {}), - o2, o; - // if unspecified, o2 is the default options object - o2 = (oAdd === _undefined ? sm2.defaultOptions : oAdd); - for(o in o2) { - if(o2.hasOwnProperty(o) && o1[o] === _undefined) { - if(typeof o2[o] !== 'object' || o2[o] === null) { - // assign directly - o1[o] = o2[o]; - } else { - // recurse through o2 - o1[o] = mixin(o1[o], o2[o]); - } - } - } - return o1; - }; - wrapCallback = function(oSound, callback) { - /** - * 03/03/2013: Fix for Flash Player 11.6.602.171 + Flash 8 (flashVersion = 8) SWF issue - * setTimeout() fix for certain SMSound callbacks like onload() and onfinish(), where subsequent calls like play() and load() fail when Flash Player 11.6.602.171 is installed, and using soundManager with flashVersion = 8 (which is the default). - * Not sure of exact cause. Suspect race condition and/or invalid (NaN-style) position argument trickling down to the next JS -> Flash _start() call, in the play() case. - * Fix: setTimeout() to yield, plus safer null / NaN checking on position argument provided to Flash. - * https://getsatisfaction.com/schillmania/topics/recent_chrome_update_seems_to_have_broken_my_sm2_audio_player - */ - if(!oSound.isHTML5 && fV === 8) { - window.setTimeout(callback, 0); - } else { - callback(); - } - }; - // additional soundManager properties that soundManager.setup() will accept - extraOptions = { - 'onready': 1, - 'ontimeout': 1, - 'defaultOptions': 1, - 'flash9Options': 1, - 'movieStarOptions': 1 - }; - assign = function(o, oParent) { - /** - * recursive assignment of properties, soundManager.setup() helper - * allows property assignment based on whitelist - */ - var i, - result = true, - hasParent = (oParent !== _undefined), - setupOptions = sm2.setupOptions, - bonusOptions = extraOptions; - // - // if soundManager.setup() called, show accepted parameters. - if(o === _undefined) { - result = []; - for(i in setupOptions) { - if(setupOptions.hasOwnProperty(i)) { - result.push(i); - } - } - for(i in bonusOptions) { - if(bonusOptions.hasOwnProperty(i)) { - if(typeof sm2[i] === 'object') { - result.push(i + ': {...}'); - } else if(sm2[i] instanceof Function) { - result.push(i + ': function() {...}'); - } else { - result.push(i); - } - } - } - sm2._wD(str('setup', result.join(', '))); - return false; - } - // - for(i in o) { - if(o.hasOwnProperty(i)) { - // if not an {object} we want to recurse through... - if(typeof o[i] !== 'object' || o[i] === null || o[i] instanceof Array || o[i] instanceof RegExp) { - // check "allowed" options - if(hasParent && bonusOptions[oParent] !== _undefined) { - // valid recursive / nested object option, eg., { defaultOptions: { volume: 50 } } - sm2[oParent][i] = o[i]; - } else if(setupOptions[i] !== _undefined) { - // special case: assign to setupOptions object, which soundManager property references - sm2.setupOptions[i] = o[i]; - // assign directly to soundManager, too - sm2[i] = o[i]; - } else if(bonusOptions[i] === _undefined) { - // invalid or disallowed parameter. complain. - complain(str((sm2[i] === _undefined ? 'setupUndef' : 'setupError'), i), 2); - result = false; - } else { - /** - * valid extraOptions (bonusOptions) parameter. - * is it a method, like onready/ontimeout? call it. - * multiple parameters should be in an array, eg. soundManager.setup({onready: [myHandler, myScope]}); - */ - if(sm2[i] instanceof Function) { - sm2[i].apply(sm2, (o[i] instanceof Array ? o[i] : [o[i]])); - } else { - // good old-fashioned direct assignment - sm2[i] = o[i]; - } - } - } else { - // recursion case, eg., { defaultOptions: { ... } } - if(bonusOptions[i] === _undefined) { - // invalid or disallowed parameter. complain. - complain(str((sm2[i] === _undefined ? 'setupUndef' : 'setupError'), i), 2); - result = false; - } else { - // recurse through object - return assign(o[i], i); - } - } - } - } - return result; - }; + // has Audio(), but is broken; let it load links directly. + sm2.hasHTML5 = false; - function preferFlashCheck(kind) { - // whether flash should play a given type - return(sm2.preferFlash && hasFlash && !sm2.ignoreFlash && (sm2.flash[kind] !== _undefined && sm2.flash[kind])); + // ignore flash case, however + sm2.html5Only = true; + + // hide the SWF, if present + if (sm2.oMC) { + sm2.oMC.style.display = 'none'; + } + + } else if (sm2.useHTML5Audio) { + + if (!sm2.html5 || !sm2.html5.canPlayType) { + sm2._wD('SoundManager: No HTML5 Audio() support detected.'); + sm2.hasHTML5 = false; } - /** - * Internal DOM2-level event helpers - * --------------------------------- - */ - event = (function() { - // normalize event methods - var old = (window.attachEvent), - evt = { - add: (old ? 'attachEvent' : 'addEventListener'), - remove: (old ? 'detachEvent' : 'removeEventListener') - }; - // normalize "on" event prefix, optional capture argument - - function getArgs(oArgs) { - var args = slice.call(oArgs), - len = args.length; - if(old) { - // prefix - args[1] = 'on' + args[1]; - if(len > 3) { - // no capture - args.pop(); - } - } else if(len === 3) { - args.push(false); - } - return args; - } - function apply(args, sType) { - // normalize and call the event method, with the proper arguments - var element = args.shift(), - method = [evt[sType]]; - if(old) { - // old IE can't do apply(). - element[method](args[0], args[1]); - } else { - element[method].apply(element, args); - } + // + if (isBadSafari) { + sm2._wD(smc + 'Note: Buggy HTML5 Audio in Safari on this OS X release, see https://bugs.webkit.org/show_bug.cgi?id=32159 - ' + (!hasFlash ? ' would use flash fallback for MP3/MP4, but none detected.' : 'will use flash fallback for MP3/MP4, if available'), 1); + } + // + + } + + if (sm2.useHTML5Audio && sm2.hasHTML5) { + + // sort out whether flash is optional, required or can be ignored. + + // innocent until proven guilty. + canIgnoreFlash = true; + + for (item in formats) { + + if (formats.hasOwnProperty(item)) { + + if (formats[item].required) { + + if (!sm2.html5.canPlayType(formats[item].type)) { + + // 100% HTML5 mode is not possible. + canIgnoreFlash = false; + flashNeeded = true; + + } else if (sm2.preferFlash && (sm2.flash[item] || sm2.flash[formats[item].type])) { + + // flash may be required, or preferred for this format. + flashNeeded = true; + } - function add() { - apply(getArgs(arguments), 'add'); - } + } + + } + + } + + } + + // sanity check... + if (sm2.ignoreFlash) { + flashNeeded = false; + canIgnoreFlash = true; + } + + sm2.html5Only = (sm2.hasHTML5 && sm2.useHTML5Audio && !flashNeeded); + + return (!sm2.html5Only); + + }; + + parseURL = function(url) { + + /** + * Internal: Finds and returns the first playable URL (or failing that, the first URL.) + * @param {string or array} url A single URL string, OR, an array of URL strings or {url:'/path/to/resource', type:'audio/mp3'} objects. + */ + + var i, j, urlResult = 0, result; + + if (url instanceof Array) { + + // find the first good one + for (i = 0, j = url.length; i < j; i++) { + + if (url[i] instanceof Object) { + + // MIME check + if (sm2.canPlayMIME(url[i].type)) { + urlResult = i; + break; + } + + } else if (sm2.canPlayURL(url[i])) { + + // URL string check + urlResult = i; + break; + + } + + } + + // normalize to string + if (url[urlResult].url) { + url[urlResult] = url[urlResult].url; + } + + result = url[urlResult]; + + } else { + + // single URL case + result = url; + + } + + return result; + + }; + + + startTimer = function(oSound) { + + /** + * attach a timer to this sound, and start an interval if needed + */ + + if (!oSound._hasTimer) { + + oSound._hasTimer = true; + + if (!mobileHTML5 && sm2.html5PollingInterval) { + + if (h5IntervalTimer === null && h5TimerCount === 0) { + + h5IntervalTimer = setInterval(timerExecute, sm2.html5PollingInterval); + + } + + h5TimerCount++; + + } + + } + + }; + + stopTimer = function(oSound) { + + /** + * detach a timer + */ + + if (oSound._hasTimer) { + + oSound._hasTimer = false; + + if (!mobileHTML5 && sm2.html5PollingInterval) { + + // interval will stop itself at next execution. + + h5TimerCount--; + + } + + } + + }; + + timerExecute = function() { + + /** + * manual polling for HTML5 progress events, ie., whileplaying() + * (can achieve greater precision than conservative default HTML5 interval) + */ + + var i; + + if (h5IntervalTimer !== null && !h5TimerCount) { + + // no active timers, stop polling interval. + + clearInterval(h5IntervalTimer); + + h5IntervalTimer = null; + + return; + + } + + // check all HTML5 sounds with timers + + for (i = sm2.soundIDs.length - 1; i >= 0; i--) { + + if (sm2.sounds[sm2.soundIDs[i]].isHTML5 && sm2.sounds[sm2.soundIDs[i]]._hasTimer) { + sm2.sounds[sm2.soundIDs[i]]._onTimer(); + } + + } + + }; + + catchError = function(options) { + + options = (options !== _undefined ? options : {}); + + if (typeof sm2.onerror === 'function') { + sm2.onerror.apply(window, [{ + type: (options.type !== _undefined ? options.type : null) + }]); + } + + if (options.fatal !== _undefined && options.fatal) { + sm2.disable(); + } + + }; + + badSafariFix = function() { + + // special case: "bad" Safari (OS X 10.3 - 10.7) must fall back to flash for MP3/MP4 + if (!isBadSafari || !detectFlash()) { + // doesn't apply + return; + } + + var aF = sm2.audioFormats, i, item; + + for (item in aF) { + + if (aF.hasOwnProperty(item)) { + + if (item === 'mp3' || item === 'mp4') { - function remove() { - apply(getArgs(arguments), 'remove'); + sm2._wD(sm + ': Using flash fallback for ' + item + ' format'); + sm2.html5[item] = false; + + // assign result to related formats, too + if (aF[item] && aF[item].related) { + for (i = aF[item].related.length - 1; i >= 0; i--) { + sm2.html5[aF[item].related[i]] = false; } - return { - 'add': add, - 'remove': remove - }; - }()); - /** - * Internal HTML5 event handling - * ----------------------------- - */ + } - function html5_event(oFn) { - // wrap html5 event handlers so we don't call them on destroyed and/or unloaded sounds - return function(e) { - var s = this._s, - result; - if(!s || !s._a) { - // - if(s && s.id) { - sm2._wD(s.id + ': Ignoring ' + e.type); - } else { - sm2._wD(h5 + 'Ignoring ' + e.type); - } - // - result = null; - } else { - result = oFn.call(this, e); - } - return result; - }; } - html5_events = { - // HTML5 event-name-to-handler map - abort: html5_event(function() { - sm2._wD(this._s.id + ': abort'); - }), - // enough has loaded to play - canplay: html5_event(function() { - var s = this._s, - position1K; - if(s._html5_canplay) { - // this event has already fired. ignore. - return true; - } - s._html5_canplay = true; - sm2._wD(s.id + ': canplay'); - s._onbufferchange(0); - // position according to instance options - position1K = (s._iO.position !== _undefined && !isNaN(s._iO.position) ? s._iO.position / msecScale : null); - // set the position if position was provided before the sound loaded - if(this.currentTime !== position1K) { - sm2._wD(s.id + ': canplay: Setting position to ' + position1K); - try { - this.currentTime = position1K; - } catch(ee) { - sm2._wD(s.id + ': canplay: Setting position of ' + position1K + ' failed: ' + ee.message, 2); - } - } - // hack for HTML5 from/to case - if(s._iO._oncanplay) { - s._iO._oncanplay(); - } - }), - canplaythrough: html5_event(function() { - var s = this._s; - if(!s.loaded) { - s._onbufferchange(0); - s._whileloading(s.bytesLoaded, s.bytesTotal, s._get_html5_duration()); - s._onload(true); - } - }), - durationchange: html5_event(function() { - // durationchange may fire at various times, probably the safest way to capture accurate/final duration. - var s = this._s, - duration; - duration = s._get_html5_duration(); - if(!isNaN(duration) && duration !== s.duration) { - sm2._wD(this._s.id + ': durationchange (' + duration + ')' + (s.duration ? ', previously ' + s.duration : '')); - s.durationEstimate = s.duration = duration; - } - }), - // TODO: Reserved for potential use - /* - emptied: html5_event(function() { - sm2._wD(this._s.id + ': emptied'); + } - }), - */ - ended: html5_event(function() { - var s = this._s; - sm2._wD(s.id + ': ended'); - s._onfinish(); - }), - error: html5_event(function() { - sm2._wD(this._s.id + ': HTML5 error, code ' + this.error.code); - /** - * HTML5 error codes, per W3C - * Error 1: Client aborted download at user's request. - * Error 2: Network error after load started. - * Error 3: Decoding issue. - * Error 4: Media (audio file) not supported. - * Reference: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#error-codes - */ - // call load with error state? - this._s._onload(false); - }), - loadeddata: html5_event(function() { - var s = this._s; - sm2._wD(s.id + ': loadeddata'); - // safari seems to nicely report progress events, eventually totalling 100% - if(!s._loaded && !isSafari) { - s.duration = s._get_html5_duration(); - } - }), - loadedmetadata: html5_event(function() { - sm2._wD(this._s.id + ': loadedmetadata'); - }), - loadstart: html5_event(function() { - sm2._wD(this._s.id + ': loadstart'); - // assume buffering at first - this._s._onbufferchange(1); - }), - play: html5_event(function() { - // sm2._wD(this._s.id + ': play()'); - // once play starts, no buffering - this._s._onbufferchange(0); - }), - playing: html5_event(function() { - sm2._wD(this._s.id + ': playing ' + String.fromCharCode(9835)); - // once play starts, no buffering - this._s._onbufferchange(0); - }), - progress: html5_event(function(e) { - // note: can fire repeatedly after "loaded" event, due to use of HTTP range/partials - var s = this._s, - i, j, progStr, buffered = 0, - isProgress = (e.type === 'progress'), - ranges = e.target.buffered, - // firefox 3.6 implements e.loaded/total (bytes) - loaded = (e.loaded || 0), - total = (e.total || 1); - // reset the "buffered" (loaded byte ranges) array - s.buffered = []; - if(ranges && ranges.length) { - // if loaded is 0, try TimeRanges implementation as % of load - // https://developer.mozilla.org/en/DOM/TimeRanges - // re-build "buffered" array - // HTML5 returns seconds. SM2 API uses msec for setPosition() etc., whether Flash or HTML5. - for(i = 0, j = ranges.length; i < j; i++) { - s.buffered.push({ - 'start': ranges.start(i) * msecScale, - 'end': ranges.end(i) * msecScale - }); - } - // use the last value locally - buffered = (ranges.end(0) - ranges.start(0)) * msecScale; - // linear case, buffer sum; does not account for seeking and HTTP partials / byte ranges - loaded = Math.min(1, buffered / (e.target.duration * msecScale)); - // - if(isProgress && ranges.length > 1) { - progStr = []; - j = ranges.length; - for(i = 0; i < j; i++) { - progStr.push(e.target.buffered.start(i) * msecScale + '-' + e.target.buffered.end(i) * msecScale); - } - sm2._wD(this._s.id + ': progress, timeRanges: ' + progStr.join(', ')); - } - if(isProgress && !isNaN(loaded)) { - sm2._wD(this._s.id + ': progress, ' + Math.floor(loaded * 100) + '% loaded'); - } - // - } - if(!isNaN(loaded)) { - // TODO: prevent calls with duplicate values. - s._whileloading(loaded, total, s._get_html5_duration()); - if(loaded && total && loaded === total) { - // in case "onload" doesn't fire (eg. gecko 1.9.2) - html5_events.canplaythrough.call(this, e); - } - } - }), - ratechange: html5_event(function() { - sm2._wD(this._s.id + ': ratechange'); - }), - suspend: html5_event(function(e) { - // download paused/stopped, may have finished (eg. onload) - var s = this._s; - sm2._wD(this._s.id + ': suspend'); - html5_events.progress.call(this, e); - s._onsuspend(); - }), - stalled: html5_event(function() { - sm2._wD(this._s.id + ': stalled'); - }), - timeupdate: html5_event(function() { - this._s._onTimer(); - }), - waiting: html5_event(function() { - var s = this._s; - // see also: seeking - sm2._wD(this._s.id + ': waiting'); - // playback faster than download rate, etc. - s._onbufferchange(1); - }) - }; - html5OK = function(iO) { - // playability test based on URL or MIME type - var result; - if(!iO || (!iO.type && !iO.url && !iO.serverURL)) { - // nothing to check - result = false; - } else if(iO.serverURL || (iO.type && preferFlashCheck(iO.type))) { - // RTMP, or preferring flash - result = false; - } else { - // Use type, if specified. Pass data: URIs to HTML5. If HTML5-only mode, no other options, so just give 'er - result = ((iO.type ? html5CanPlay({ - type: iO.type - }) : html5CanPlay({ - url: iO.url - }) || sm2.html5Only || iO.url.match(/data\:/i))); - } - return result; - }; - html5Unload = function(oAudio) { - /** - * Internal method: Unload media, and cancel any current/pending network requests. - * Firefox can load an empty URL, which allegedly destroys the decoder and stops the download. - * https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox#Stopping_the_download_of_media - * However, Firefox has been seen loading a relative URL from '' and thus requesting the hosting page on unload. - * Other UA behaviour is unclear, so everyone else gets an about:blank-style URL. - */ - var url; - if(oAudio) { - // Firefox and Chrome accept short WAVe data: URIs. Chome dislikes audio/wav, but accepts audio/wav for data: MIME. - // Desktop Safari complains / fails on data: URI, so it gets about:blank. - url = (isSafari ? emptyURL : (sm2.html5.canPlayType('audio/wav') ? emptyWAV : emptyURL)); - oAudio.src = url; - // reset some state, too - if(oAudio._called_unload !== undefined) { - oAudio._called_load = false; - } - } - if(useGlobalHTML5Audio) { - // ensure URL state is trashed, also - lastGlobalHTML5URL = null; - } - return url; - }; - html5CanPlay = function(o) { - /** - * Try to find MIME, test and return truthiness - * o = { - * url: '/path/to/an.mp3', - * type: 'audio/mp3' - * } - */ - if(!sm2.useHTML5Audio || !sm2.hasHTML5) { - return false; - } - var url = (o.url || null), - mime = (o.type || null), - aF = sm2.audioFormats, - result, - offset, - fileExt, - item; - // account for known cases like audio/mp3 - if(mime && sm2.html5[mime] !== _undefined) { - return(sm2.html5[mime] && !preferFlashCheck(mime)); - } - if(!html5Ext) { - html5Ext = []; - for(item in aF) { - if(aF.hasOwnProperty(item)) { - html5Ext.push(item); - if(aF[item].related) { - html5Ext = html5Ext.concat(aF[item].related); - } - } - } - html5Ext = new RegExp('\\.(' + html5Ext.join('|') + ')(\\?.*)?$', 'i'); - } - // TODO: Strip URL queries, etc. - fileExt = (url ? url.toLowerCase().match(html5Ext) : null); - if(!fileExt || !fileExt.length) { - if(!mime) { - result = false; - } else { - // audio/mp3 -> mp3, result should be known - offset = mime.indexOf(';'); - // strip "audio/X; codecs..." - fileExt = (offset !== -1 ? mime.substr(0, offset) : mime).substr(6); - } - } else { - // match the raw extension name - "mp3", for example - fileExt = fileExt[1]; - } - if(fileExt && sm2.html5[fileExt] !== _undefined) { - // result known - result = (sm2.html5[fileExt] && !preferFlashCheck(fileExt)); - } else { - mime = 'audio/' + fileExt; - result = sm2.html5.canPlayType({ - type: mime - }); - sm2.html5[fileExt] = result; - // sm2._wD('canPlayType, found result: ' + result); - result = (result && sm2.html5[mime] && !preferFlashCheck(mime)); - } - return result; - }; - testHTML5 = function() { - /** - * Internal: Iterates over audioFormats, determining support eg. audio/mp3, audio/mpeg and so on - * assigns results to html5[] and flash[]. - */ - if(!sm2.useHTML5Audio || !sm2.hasHTML5) { - // without HTML5, we need Flash. - sm2.html5.usingFlash = true; - needsFlash = true; - return false; - } - // double-whammy: Opera 9.64 throws WRONG_ARGUMENTS_ERR if no parameter passed to Audio(), and Webkit + iOS happily tries to load "null" as a URL. :/ - var a = (Audio !== _undefined ? (isOpera && opera.version() < 10 ? new Audio(null) : new Audio()) : null), - item, lookup, support = {}, aF, i; - - function cp(m) { - var canPlay, j, - result = false, - isOK = false; - if(!a || typeof a.canPlayType !== 'function') { - return result; - } - if(m instanceof Array) { - // iterate through all mime types, return any successes - for(i = 0, j = m.length; i < j; i++) { - if(sm2.html5[m[i]] || a.canPlayType(m[i]).match(sm2.html5Test)) { - isOK = true; - sm2.html5[m[i]] = true; - // note flash support, too - sm2.flash[m[i]] = !! (m[i].match(flashMIME)); - } - } - result = isOK; - } else { - canPlay = (a && typeof a.canPlayType === 'function' ? a.canPlayType(m) : false); - result = !! (canPlay && (canPlay.match(sm2.html5Test))); - } - return result; - } - // test all registered formats + codecs - aF = sm2.audioFormats; - for(item in aF) { - if(aF.hasOwnProperty(item)) { - lookup = 'audio/' + item; - support[item] = cp(aF[item].type); - // write back generic type too, eg. audio/mp3 - support[lookup] = support[item]; - // assign flash - if(item.match(flashMIME)) { - sm2.flash[item] = true; - sm2.flash[lookup] = true; - } else { - sm2.flash[item] = false; - sm2.flash[lookup] = false; - } - // assign result to related formats, too - if(aF[item] && aF[item].related) { - for(i = aF[item].related.length - 1; i >= 0; i--) { - // eg. audio/m4a - support['audio/' + aF[item].related[i]] = support[item]; - sm2.html5[aF[item].related[i]] = support[item]; - sm2.flash[aF[item].related[i]] = support[item]; - } - } - } - } - support.canPlayType = (a ? cp : null); - sm2.html5 = mixin(sm2.html5, support); - sm2.html5.usingFlash = featureCheck(); - needsFlash = sm2.html5.usingFlash; - return true; - }; - strings = { - // - notReady: 'Unavailable - wait until onready() has fired.', - notOK: 'Audio support is not available.', - domError: sm + 'exception caught while appending SWF to DOM.', - spcWmode: 'Removing wmode, preventing known SWF loading issue(s)', - swf404: smc + 'Verify that %s is a valid path.', - tryDebug: 'Try ' + sm + '.debugFlash = true for more security details (output goes to SWF.)', - checkSWF: 'See SWF output for more debug info.', - localFail: smc + 'Non-HTTP page (' + doc.location.protocol + ' URL?) Review Flash player security settings for this special case:\nhttp://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html\nMay need to add/allow path, eg. c:/sm2/ or /users/me/sm2/', - waitFocus: smc + 'Special case: Waiting for SWF to load with window focus...', - waitForever: smc + 'Waiting indefinitely for Flash (will recover if unblocked)...', - waitSWF: smc + 'Waiting for 100% SWF load...', - needFunction: smc + 'Function object expected for %s', - badID: 'Sound ID "%s" should be a string, starting with a non-numeric character', - currentObj: smc + '_debug(): Current sound objects', - waitOnload: smc + 'Waiting for window.onload()', - docLoaded: smc + 'Document already loaded', - onload: smc + 'initComplete(): calling soundManager.onload()', - onloadOK: sm + '.onload() complete', - didInit: smc + 'init(): Already called?', - secNote: 'Flash security note: Network/internet URLs will not load due to security restrictions. Access can be configured via Flash Player Global Security Settings Page: http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html', - badRemove: smc + 'Failed to remove Flash node.', - shutdown: sm + '.disable(): Shutting down', - queue: smc + 'Queueing %s handler', - smError: 'SMSound.load(): Exception: JS-Flash communication failed, or JS error.', - fbTimeout: 'No flash response, applying .' + swfCSS.swfTimedout + ' CSS...', - fbLoaded: 'Flash loaded', - fbHandler: smc + 'flashBlockHandler()', - manURL: 'SMSound.load(): Using manually-assigned URL', - onURL: sm + '.load(): current URL already assigned.', - badFV: sm + '.flashVersion must be 8 or 9. "%s" is invalid. Reverting to %s.', - as2loop: 'Note: Setting stream:false so looping can work (flash 8 limitation)', - noNSLoop: 'Note: Looping not implemented for MovieStar formats', - needfl9: 'Note: Switching to flash 9, required for MP4 formats.', - mfTimeout: 'Setting flashLoadTimeout = 0 (infinite) for off-screen, mobile flash case', - needFlash: smc + 'Fatal error: Flash is needed to play some required formats, but is not available.', - gotFocus: smc + 'Got window focus.', - policy: 'Enabling usePolicyFile for data access', - setup: sm + '.setup(): allowed parameters: %s', - setupError: sm + '.setup(): "%s" cannot be assigned with this method.', - setupUndef: sm + '.setup(): Could not find option "%s"', - setupLate: sm + '.setup(): url, flashVersion and html5Test property changes will not take effect until reboot().', - noURL: smc + 'Flash URL required. Call soundManager.setup({url:...}) to get started.', - sm2Loaded: 'SoundManager 2: Ready. ' + String.fromCharCode(10003), - reset: sm + '.reset(): Removing event callbacks', - mobileUA: 'Mobile UA detected, preferring HTML5 by default.', - globalHTML5: 'Using singleton HTML5 Audio() pattern for this device.' - // - }; - str = function() { - // internal string replace helper. - // arguments: o [,items to replace] - // - var args, - i, j, o, - sstr; - // real array, please - args = slice.call(arguments); - // first argument - o = args.shift(); - sstr = (strings && strings[o] ? strings[o] : ''); - if(sstr && args && args.length) { - for(i = 0, j = args.length; i < j; i++) { - sstr = sstr.replace('%s', args[i]); - } - } - return sstr; - // - }; - loopFix = function(sOpt) { - // flash 8 requires stream = false for looping to work - if(fV === 8 && sOpt.loops > 1 && sOpt.stream) { - _wDS('as2loop'); - sOpt.stream = false; - } - return sOpt; - }; - policyFix = function(sOpt, sPre) { - if(sOpt && !sOpt.usePolicyFile && (sOpt.onid3 || sOpt.usePeakData || sOpt.useWaveformData || sOpt.useEQData)) { - sm2._wD((sPre || '') + str('policy')); - sOpt.usePolicyFile = true; - } - return sOpt; - }; - complain = function(sMsg) { - // - if(hasConsole && console.warn !== _undefined) { - console.warn(sMsg); - } else { - sm2._wD(sMsg); - } - // - }; - doNothing = function() { - return false; - }; - disableObject = function(o) { - var oProp; - for(oProp in o) { - if(o.hasOwnProperty(oProp) && typeof o[oProp] === 'function') { - o[oProp] = doNothing; - } - } - oProp = null; - }; - failSafely = function(bNoDisable) { - // general failure exception handler - if(bNoDisable === _undefined) { - bNoDisable = false; - } - if(disabled || bNoDisable) { - sm2.disable(bNoDisable); - } - }; - normalizeMovieURL = function(smURL) { - var urlParams = null, - url; - if(smURL) { - if(smURL.match(/\.swf(\?.*)?$/i)) { - urlParams = smURL.substr(smURL.toLowerCase().lastIndexOf('.swf?') + 4); - if(urlParams) { - // assume user knows what they're doing - return smURL; - } - } else if(smURL.lastIndexOf('/') !== smURL.length - 1) { - // append trailing slash, if needed - smURL += '/'; - } - } - url = (smURL && smURL.lastIndexOf('/') !== -1 ? smURL.substr(0, smURL.lastIndexOf('/') + 1) : './') + sm2.movieURL; - if(sm2.noSWFCache) { - url += ('?ts=' + new Date().getTime()); - } - return url; - }; - setVersionInfo = function() { - // short-hand for internal use - fV = parseInt(sm2.flashVersion, 10); - if(fV !== 8 && fV !== 9) { - sm2._wD(str('badFV', fV, defaultFlashVersion)); - sm2.flashVersion = fV = defaultFlashVersion; - } - // debug flash movie, if applicable - var isDebug = (sm2.debugMode || sm2.debugFlash ? '_debug.swf' : '.swf'); - if(sm2.useHTML5Audio && !sm2.html5Only && sm2.audioFormats.mp4.required && fV < 9) { - sm2._wD(str('needfl9')); - sm2.flashVersion = fV = 9; - } - sm2.version = sm2.versionNumber + (sm2.html5Only ? ' (HTML5-only mode)' : (fV === 9 ? ' (AS3/Flash 9)' : ' (AS2/Flash 8)')); - // set up default options - if(fV > 8) { - // +flash 9 base options - sm2.defaultOptions = mixin(sm2.defaultOptions, sm2.flash9Options); - sm2.features.buffering = true; - // +moviestar support - sm2.defaultOptions = mixin(sm2.defaultOptions, sm2.movieStarOptions); - sm2.filePatterns.flash9 = new RegExp('\\.(mp3|' + netStreamTypes.join('|') + ')(\\?.*)?$', 'i'); - sm2.features.movieStar = true; - } else { - sm2.features.movieStar = false; - } - // regExp for flash canPlay(), etc. - sm2.filePattern = sm2.filePatterns[(fV !== 8 ? 'flash9' : 'flash8')]; - // if applicable, use _debug versions of SWFs - sm2.movieURL = (fV === 8 ? 'soundmanager2.swf' : 'soundmanager2_flash9.swf').replace('.swf', isDebug); - sm2.features.peakData = sm2.features.waveformData = sm2.features.eqData = (fV > 8); - }; - setPolling = function(bPolling, bHighPerformance) { - if(!flash) { - return false; - } - flash._setPolling(bPolling, bHighPerformance); - }; - initDebug = function() { - // starts debug mode, creating output
for UAs without console object - // allow force of debug mode via URL - // - if(sm2.debugURLParam.test(wl)) { - sm2.debugMode = true; - } - if(id(sm2.debugID)) { - return false; - } - var oD, oDebug, oTarget, oToggle, tmp; - if(sm2.debugMode && !id(sm2.debugID) && (!hasConsole || !sm2.useConsole || !sm2.consoleOnly)) { - oD = doc.createElement('div'); - oD.id = sm2.debugID + '-toggle'; - oToggle = { - 'position': 'fixed', - 'bottom': '0px', - 'right': '0px', - 'width': '1.2em', - 'height': '1.2em', - 'lineHeight': '1.2em', - 'margin': '2px', - 'textAlign': 'center', - 'border': '1px solid #999', - 'cursor': 'pointer', - 'background': '#fff', - 'color': '#333', - 'zIndex': 10001 - }; - oD.appendChild(doc.createTextNode('-')); - oD.onclick = toggleDebug; - oD.title = 'Toggle SM2 debug console'; - if(ua.match(/msie 6/i)) { - oD.style.position = 'absolute'; - oD.style.cursor = 'hand'; - } - for(tmp in oToggle) { - if(oToggle.hasOwnProperty(tmp)) { - oD.style[tmp] = oToggle[tmp]; - } - } - oDebug = doc.createElement('div'); - oDebug.id = sm2.debugID; - oDebug.style.display = (sm2.debugMode ? 'block' : 'none'); - if(sm2.debugMode && !id(oD.id)) { - try { - oTarget = getDocument(); - oTarget.appendChild(oD); - } catch(e2) { - throw new Error(str('domError') + ' \n' + e2.toString()); - } - oTarget.appendChild(oDebug); - } - } - oTarget = null; - // - }; - idCheck = this.getSoundById; - // - _wDS = function(o, errorLevel) { - return(!o ? '' : sm2._wD(str(o), errorLevel)); - }; - toggleDebug = function() { - var o = id(sm2.debugID), - oT = id(sm2.debugID + '-toggle'); - if(!o) { - return false; - } - if(debugOpen) { - // minimize - oT.innerHTML = '+'; - o.style.display = 'none'; - } else { - oT.innerHTML = '-'; - o.style.display = 'block'; - } - debugOpen = !debugOpen; - }; - debugTS = function(sEventType, bSuccess, sMessage) { - // troubleshooter debug hooks - if(window.sm2Debugger !== _undefined) { - try { - sm2Debugger.handleEvent(sEventType, bSuccess, sMessage); - } catch(e) { - // oh well - return false; - } - } - return true; - }; - // - getSWFCSS = function() { - var css = []; - if(sm2.debugMode) { - css.push(swfCSS.sm2Debug); - } - if(sm2.debugFlash) { - css.push(swfCSS.flashDebug); - } - if(sm2.useHighPerformance) { - css.push(swfCSS.highPerf); - } - return css.join(' '); - }; - flashBlockHandler = function() { - // *possible* flash block situation. - var name = str('fbHandler'), - p = sm2.getMoviePercent(), - css = swfCSS, - error = { - type: 'FLASHBLOCK' - }; - if(sm2.html5Only) { - // no flash, or unused - return false; - } - if(!sm2.ok()) { - if(needsFlash) { - // make the movie more visible, so user can fix - sm2.oMC.className = getSWFCSS() + ' ' + css.swfDefault + ' ' + (p === null ? css.swfTimedout : css.swfError); - sm2._wD(name + ': ' + str('fbTimeout') + (p ? ' (' + str('fbLoaded') + ')' : '')); - } - sm2.didFlashBlock = true; - // fire onready(), complain lightly - processOnEvents({ - type: 'ontimeout', - ignoreInit: true, - error: error - }); - catchError(error); - } else { - // SM2 loaded OK (or recovered) - // - if(sm2.didFlashBlock) { - sm2._wD(name + ': Unblocked'); - } - // - if(sm2.oMC) { - sm2.oMC.className = [getSWFCSS(), css.swfDefault, css.swfLoaded + (sm2.didFlashBlock ? ' ' + css.swfUnblocked : '')].join(' '); - } - } - }; - addOnEvent = function(sType, oMethod, oScope) { - if(on_queue[sType] === _undefined) { - on_queue[sType] = []; - } - on_queue[sType].push({ - 'method': oMethod, - 'scope': (oScope || null), - 'fired': false - }); - }; - processOnEvents = function(oOptions) { - // if unspecified, assume OK/error - if(!oOptions) { - oOptions = { - type: (sm2.ok() ? 'onready' : 'ontimeout') - }; - } - if(!didInit && oOptions && !oOptions.ignoreInit) { - // not ready yet. - return false; - } - if(oOptions.type === 'ontimeout' && (sm2.ok() || (disabled && !oOptions.ignoreInit))) { - // invalid case - return false; - } - var status = { - success: (oOptions && oOptions.ignoreInit ? sm2.ok() : !disabled) - }, - // queue specified by type, or none - srcQueue = (oOptions && oOptions.type ? on_queue[oOptions.type] || [] : []), - queue = [], - i, j, - args = [status], - canRetry = (needsFlash && !sm2.ok()); - if(oOptions.error) { - args[0].error = oOptions.error; - } - for(i = 0, j = srcQueue.length; i < j; i++) { - if(srcQueue[i].fired !== true) { - queue.push(srcQueue[i]); - } - } - if(queue.length) { - // sm2._wD(sm + ': Firing ' + queue.length + ' ' + oOptions.type + '() item' + (queue.length === 1 ? '' : 's')); - for(i = 0, j = queue.length; i < j; i++) { - if(queue[i].scope) { - queue[i].method.apply(queue[i].scope, args); - } else { - queue[i].method.apply(this, args); - } - if(!canRetry) { - // useFlashBlock and SWF timeout case doesn't count here. - queue[i].fired = true; - } - } - } - return true; - }; - initUserOnload = function() { - window.setTimeout(function() { - if(sm2.useFlashBlock) { - flashBlockHandler(); - } - processOnEvents(); - // call user-defined "onload", scoped to window - if(typeof sm2.onload === 'function') { - _wDS('onload', 1); - sm2.onload.apply(window); - _wDS('onloadOK', 1); - } - if(sm2.waitForWindowLoad) { - event.add(window, 'load', initUserOnload); - } - }, 1); - }; - detectFlash = function() { - // hat tip: Flash Detect library (BSD, (C) 2007) by Carl "DocYes" S. Yestrau - http://featureblend.com/javascript-flash-detection-library.html / http://featureblend.com/license.txt - if(hasFlash !== _undefined) { - // this work has already been done. - return hasFlash; - } - var hasPlugin = false, - n = navigator, - nP = n.plugins, - obj, type, types, AX = window.ActiveXObject; - if(nP && nP.length) { - type = 'application/x-shockwave-flash'; - types = n.mimeTypes; - if(types && types[type] && types[type].enabledPlugin && types[type].enabledPlugin.description) { - hasPlugin = true; - } - } else if(AX !== _undefined && !ua.match(/MSAppHost/i)) { - // Windows 8 Store Apps (MSAppHost) are weird (compatibility?) and won't complain here, but will barf if Flash/ActiveX object is appended to the DOM. - try { - obj = new AX('ShockwaveFlash.ShockwaveFlash'); - } catch(e) { - // oh well - obj = null; - } - hasPlugin = ( !! obj); - // cleanup, because it is ActiveX after all - obj = null; - } - hasFlash = hasPlugin; - return hasPlugin; - }; - featureCheck = function() { - var flashNeeded, - item, - formats = sm2.audioFormats, - // iPhone <= 3.1 has broken HTML5 audio(), but firmware 3.2 (original iPad) + iOS4 works. - isSpecial = (is_iDevice && !! (ua.match(/os (1|2|3_0|3_1)\s/i))); - if(isSpecial) { - // has Audio(), but is broken; let it load links directly. - sm2.hasHTML5 = false; - // ignore flash case, however - sm2.html5Only = true; - // hide the SWF, if present - if(sm2.oMC) { - sm2.oMC.style.display = 'none'; - } - } else { - if(sm2.useHTML5Audio) { - if(!sm2.html5 || !sm2.html5.canPlayType) { - sm2._wD('SoundManager: No HTML5 Audio() support detected.'); - sm2.hasHTML5 = false; - } - // - if(isBadSafari) { - sm2._wD(smc + 'Note: Buggy HTML5 Audio in Safari on this OS X release, see https://bugs.webkit.org/show_bug.cgi?id=32159 - ' + (!hasFlash ? ' would use flash fallback for MP3/MP4, but none detected.' : 'will use flash fallback for MP3/MP4, if available'), 1); - } - // - } - } - if(sm2.useHTML5Audio && sm2.hasHTML5) { - // sort out whether flash is optional, required or can be ignored. - // innocent until proven guilty. - canIgnoreFlash = true; - for(item in formats) { - if(formats.hasOwnProperty(item)) { - if(formats[item].required) { - if(!sm2.html5.canPlayType(formats[item].type)) { - // 100% HTML5 mode is not possible. - canIgnoreFlash = false; - flashNeeded = true; - } else if(sm2.preferFlash && (sm2.flash[item] || sm2.flash[formats[item].type])) { - // flash may be required, or preferred for this format. - flashNeeded = true; - } - } - } - } - } - // sanity check... - if(sm2.ignoreFlash) { - flashNeeded = false; - canIgnoreFlash = true; - } - sm2.html5Only = (sm2.hasHTML5 && sm2.useHTML5Audio && !flashNeeded); - return(!sm2.html5Only); - }; - parseURL = function(url) { - /** - * Internal: Finds and returns the first playable URL (or failing that, the first URL.) - * @param {string or array} url A single URL string, OR, an array of URL strings or {url:'/path/to/resource', type:'audio/mp3'} objects. - */ - var i, j, urlResult = 0, - result; - if(url instanceof Array) { - // find the first good one - for(i = 0, j = url.length; i < j; i++) { - if(url[i] instanceof Object) { - // MIME check - if(sm2.canPlayMIME(url[i].type)) { - urlResult = i; - break; - } - } else if(sm2.canPlayURL(url[i])) { - // URL string check - urlResult = i; - break; - } - } - // normalize to string - if(url[urlResult].url) { - url[urlResult] = url[urlResult].url; - } - result = url[urlResult]; - } else { - // single URL case - result = url; - } - return result; - }; - startTimer = function(oSound) { - /** - * attach a timer to this sound, and start an interval if needed - */ - if(!oSound._hasTimer) { - oSound._hasTimer = true; - if(!mobileHTML5 && sm2.html5PollingInterval) { - if(h5IntervalTimer === null && h5TimerCount === 0) { - h5IntervalTimer = setInterval(timerExecute, sm2.html5PollingInterval); - } - h5TimerCount++; - } - } - }; - stopTimer = function(oSound) { - /** - * detach a timer - */ - if(oSound._hasTimer) { - oSound._hasTimer = false; - if(!mobileHTML5 && sm2.html5PollingInterval) { - // interval will stop itself at next execution. - h5TimerCount--; - } - } - }; - timerExecute = function() { - /** - * manual polling for HTML5 progress events, ie., whileplaying() (can achieve greater precision than conservative default HTML5 interval) - */ - var i; - if(h5IntervalTimer !== null && !h5TimerCount) { - // no active timers, stop polling interval. - clearInterval(h5IntervalTimer); - h5IntervalTimer = null; - return false; - } - // check all HTML5 sounds with timers - for(i = sm2.soundIDs.length - 1; i >= 0; i--) { - if(sm2.sounds[sm2.soundIDs[i]].isHTML5 && sm2.sounds[sm2.soundIDs[i]]._hasTimer) { - sm2.sounds[sm2.soundIDs[i]]._onTimer(); - } - } - }; - catchError = function(options) { - options = (options !== _undefined ? options : {}); - if(typeof sm2.onerror === 'function') { - sm2.onerror.apply(window, [{ - type: (options.type !== _undefined ? options.type : null) - }]); - } - if(options.fatal !== _undefined && options.fatal) { - sm2.disable(); - } - }; - badSafariFix = function() { - // special case: "bad" Safari (OS X 10.3 - 10.7) must fall back to flash for MP3/MP4 - if(!isBadSafari || !detectFlash()) { - // doesn't apply - return false; - } - var aF = sm2.audioFormats, - i, item; - for(item in aF) { - if(aF.hasOwnProperty(item)) { - if(item === 'mp3' || item === 'mp4') { - sm2._wD(sm + ': Using flash fallback for ' + item + ' format'); - sm2.html5[item] = false; - // assign result to related formats, too - if(aF[item] && aF[item].related) { - for(i = aF[item].related.length - 1; i >= 0; i--) { - sm2.html5[aF[item].related[i]] = false; - } - } - } - } - } - }; - /** - * Pseudo-private flash/ExternalInterface methods - * ---------------------------------------------- - */ - this._setSandboxType = function(sandboxType) { - // - var sb = sm2.sandbox; - sb.type = sandboxType; - sb.description = sb.types[(sb.types[sandboxType] !== _undefined ? sandboxType : 'unknown')]; - if(sb.type === 'localWithFile') { - sb.noRemote = true; - sb.noLocal = false; - _wDS('secNote', 2); - } else if(sb.type === 'localWithNetwork') { - sb.noRemote = false; - sb.noLocal = true; - } else if(sb.type === 'localTrusted') { - sb.noRemote = false; - sb.noLocal = false; - } - // - }; - this._externalInterfaceOK = function(swfVersion) { - // flash callback confirming flash loaded, EI working etc. - // swfVersion: SWF build string - if(sm2.swfLoaded) { - return false; - } - var e; - debugTS('swf', true); - debugTS('flashtojs', true); - sm2.swfLoaded = true; - tryInitOnFocus = false; - if(isBadSafari) { - badSafariFix(); - } - // complain if JS + SWF build/version strings don't match, excluding +DEV builds - // - if(!swfVersion || swfVersion.replace(/\+dev/i, '') !== sm2.versionNumber.replace(/\+dev/i, '')) { - e = sm + ': Fatal: JavaScript file build "' + sm2.versionNumber + '" does not match Flash SWF build "' + swfVersion + '" at ' + sm2.url + '. Ensure both are up-to-date.'; - // escape flash -> JS stack so this error fires in window. - setTimeout(function versionMismatch() { - throw new Error(e); - }, 0); - // exit, init will fail with timeout - return false; - } - // - // IE needs a larger timeout - setTimeout(init, isIE ? 100 : 1); - }; - /** - * Private initialization helpers - * ------------------------------ - */ - createMovie = function(smID, smURL) { - if(didAppend && appendSuccess) { - // ignore if already succeeded - return false; - } + } + + }; + + /** + * Pseudo-private flash/ExternalInterface methods + * ---------------------------------------------- + */ + + this._setSandboxType = function(sandboxType) { + + // + // Security sandbox according to Flash plugin + var sb = sm2.sandbox; + + sb.type = sandboxType; + sb.description = sb.types[(sb.types[sandboxType] !== _undefined ? sandboxType : 'unknown')]; + + if (sb.type === 'localWithFile') { + + sb.noRemote = true; + sb.noLocal = false; + _wDS('secNote', 2); + + } else if (sb.type === 'localWithNetwork') { + + sb.noRemote = false; + sb.noLocal = true; + + } else if (sb.type === 'localTrusted') { + + sb.noRemote = false; + sb.noLocal = false; + + } + // + + }; + + this._externalInterfaceOK = function(swfVersion) { + + // flash callback confirming flash loaded, EI working etc. + // swfVersion: SWF build string + + if (sm2.swfLoaded) { + return; + } + + var e; + + debugTS('swf', true); + debugTS('flashtojs', true); + sm2.swfLoaded = true; + tryInitOnFocus = false; - function initMsg() { - // - var options = [], - title, - msg = [], - delimiter = ' + '; - title = 'SoundManager ' + sm2.version + (!sm2.html5Only && sm2.useHTML5Audio ? (sm2.hasHTML5 ? ' + HTML5 audio' : ', no HTML5 audio support') : ''); - if(!sm2.html5Only) { - if(sm2.preferFlash) { - options.push('preferFlash'); - } - if(sm2.useHighPerformance) { - options.push('useHighPerformance'); - } - if(sm2.flashPollingInterval) { - options.push('flashPollingInterval (' + sm2.flashPollingInterval + 'ms)'); - } - if(sm2.html5PollingInterval) { - options.push('html5PollingInterval (' + sm2.html5PollingInterval + 'ms)'); - } - if(sm2.wmode) { - options.push('wmode (' + sm2.wmode + ')'); - } - if(sm2.debugFlash) { - options.push('debugFlash'); - } - if(sm2.useFlashBlock) { - options.push('flashBlock'); - } - } else { - if(sm2.html5PollingInterval) { - options.push('html5PollingInterval (' + sm2.html5PollingInterval + 'ms)'); - } - } - if(options.length) { - msg = msg.concat([options.join(delimiter)]); - } - sm2._wD(title + (msg.length ? delimiter + msg.join(', ') : ''), 1); - showSupport(); - // - } - if(sm2.html5Only) { - // 100% HTML5 mode - setVersionInfo(); - initMsg(); - sm2.oMC = id(sm2.movieID); - init(); - // prevent multiple init attempts - didAppend = true; - appendSuccess = true; - return false; - } - // flash path - var remoteURL = (smURL || sm2.url), - localURL = (sm2.altURL || remoteURL), - swfTitle = 'JS/Flash audio component (SoundManager 2)', - oTarget = getDocument(), - extraClass = getSWFCSS(), - isRTL = null, - html = doc.getElementsByTagName('html')[0], - oEmbed, oMovie, tmp, movieHTML, oEl, s, x, sClass; - isRTL = (html && html.dir && html.dir.match(/rtl/i)); - smID = (smID === _undefined ? sm2.id : smID); - - function param(name, value) { - return ''; - } - // safety check for legacy (change to Flash 9 URL) - setVersionInfo(); - sm2.url = normalizeMovieURL(overHTTP ? remoteURL : localURL); - smURL = sm2.url; - sm2.wmode = (!sm2.wmode && sm2.useHighPerformance ? 'transparent' : sm2.wmode); - if(sm2.wmode !== null && (ua.match(/msie 8/i) || (!isIE && !sm2.useHighPerformance)) && navigator.platform.match(/win32|win64/i)) { - /** - * extra-special case: movie doesn't load until scrolled into view when using wmode = anything but 'window' here - * does not apply when using high performance (position:fixed means on-screen), OR infinite flash load timeout - * wmode breaks IE 8 on Vista + Win7 too in some cases, as of January 2011 (?) - */ - messages.push(strings.spcWmode); - sm2.wmode = null; - } - oEmbed = { - 'name': smID, - 'id': smID, - 'src': smURL, - 'quality': 'high', - 'allowScriptAccess': sm2.allowScriptAccess, - 'bgcolor': sm2.bgColor, - 'pluginspage': http + 'www.macromedia.com/go/getflashplayer', - 'title': swfTitle, - 'type': 'application/x-shockwave-flash', - 'wmode': sm2.wmode, - // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html - 'hasPriority': 'true' + if (isBadSafari) { + badSafariFix(); + } + + // complain if JS + SWF build/version strings don't match, excluding +DEV builds + // + if (!swfVersion || swfVersion.replace(/\+dev/i, '') !== sm2.versionNumber.replace(/\+dev/i, '')) { + + e = sm + ': Fatal: JavaScript file build "' + sm2.versionNumber + '" does not match Flash SWF build "' + swfVersion + '" at ' + sm2.url + '. Ensure both are up-to-date.'; + + // escape flash -> JS stack so this error fires in window. + setTimeout(function() { + throw new Error(e); + }, 0); + + // exit, init will fail with timeout + return; + + } + // + + // IE needs a larger timeout + setTimeout(init, isIE ? 100 : 1); + + }; + + /** + * Private initialization helpers + * ------------------------------ + */ + + createMovie = function(movieID, movieURL) { + + // ignore if already connected + if (didAppend && appendSuccess) return false; + + function initMsg() { + + // + + var options = [], + title, + msg = [], + delimiter = ' + '; + + title = 'SoundManager ' + sm2.version + (!sm2.html5Only && sm2.useHTML5Audio ? (sm2.hasHTML5 ? ' + HTML5 audio' : ', no HTML5 audio support') : ''); + + if (!sm2.html5Only) { + + if (sm2.preferFlash) { + options.push('preferFlash'); + } + + if (sm2.useHighPerformance) { + options.push('useHighPerformance'); + } + + if (sm2.flashPollingInterval) { + options.push('flashPollingInterval (' + sm2.flashPollingInterval + 'ms)'); + } + + if (sm2.html5PollingInterval) { + options.push('html5PollingInterval (' + sm2.html5PollingInterval + 'ms)'); + } + + if (sm2.wmode) { + options.push('wmode (' + sm2.wmode + ')'); + } + + if (sm2.debugFlash) { + options.push('debugFlash'); + } + + if (sm2.useFlashBlock) { + options.push('flashBlock'); + } + + } else if (sm2.html5PollingInterval) { + options.push('html5PollingInterval (' + sm2.html5PollingInterval + 'ms)'); + } + + if (options.length) { + msg = msg.concat([options.join(delimiter)]); + } + + sm2._wD(title + (msg.length ? delimiter + msg.join(', ') : ''), 1); + + showSupport(); + + // + + } + + if (sm2.html5Only) { + + // 100% HTML5 mode + setVersionInfo(); + + initMsg(); + sm2.oMC = id(sm2.movieID); + init(); + + // prevent multiple init attempts + didAppend = true; + + appendSuccess = true; + + return false; + + } + + // flash path + var remoteURL = (movieURL || sm2.url), + localURL = (sm2.altURL || remoteURL), + swfTitle = 'JS/Flash audio component (SoundManager 2)', + oTarget = getDocument(), + extraClass = getSWFCSS(), + isRTL = null, + html = doc.getElementsByTagName('html')[0], + oEmbed, oMovie, tmp, movieHTML, oEl, s, x, sClass; + + isRTL = (html && html.dir && html.dir.match(/rtl/i)); + movieID = (movieID === _undefined ? sm2.id : movieID); + + function param(name, value) { + return ''; + } + + // safety check for legacy (change to Flash 9 URL) + setVersionInfo(); + sm2.url = normalizeMovieURL(overHTTP ? remoteURL : localURL); + movieURL = sm2.url; + + sm2.wmode = (!sm2.wmode && sm2.useHighPerformance ? 'transparent' : sm2.wmode); + + if (sm2.wmode !== null && (ua.match(/msie 8/i) || (!isIE && !sm2.useHighPerformance)) && navigator.platform.match(/win32|win64/i)) { + /** + * extra-special case: movie doesn't load until scrolled into view when using wmode = anything but 'window' here + * does not apply when using high performance (position:fixed means on-screen), OR infinite flash load timeout + * wmode breaks IE 8 on Vista + Win7 too in some cases, as of January 2011 (?) + */ + messages.push(strings.spcWmode); + sm2.wmode = null; + } + + oEmbed = { + name: movieID, + id: movieID, + src: movieURL, + quality: 'high', + allowScriptAccess: sm2.allowScriptAccess, + bgcolor: sm2.bgColor, + pluginspage: http + 'www.macromedia.com/go/getflashplayer', + title: swfTitle, + type: 'application/x-shockwave-flash', + wmode: sm2.wmode, + // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html + hasPriority: 'true' + }; + + if (sm2.debugFlash) { + oEmbed.FlashVars = 'debug=1'; + } + + if (!sm2.wmode) { + // don't write empty attribute + delete oEmbed.wmode; + } + + if (isIE) { + + // IE is "special". + oMovie = doc.createElement('div'); + movieHTML = [ + '', + param('movie', movieURL), + param('AllowScriptAccess', sm2.allowScriptAccess), + param('quality', oEmbed.quality), + (sm2.wmode ? param('wmode', sm2.wmode) : ''), + param('bgcolor', sm2.bgColor), + param('hasPriority', 'true'), + (sm2.debugFlash ? param('FlashVars', oEmbed.FlashVars) : ''), + '' + ].join(''); + + } else { + + oMovie = doc.createElement('embed'); + for (tmp in oEmbed) { + if (oEmbed.hasOwnProperty(tmp)) { + oMovie.setAttribute(tmp, oEmbed[tmp]); + } + } + + } + + initDebug(); + extraClass = getSWFCSS(); + oTarget = getDocument(); + + if (oTarget) { + + sm2.oMC = (id(sm2.movieID) || doc.createElement('div')); + + if (!sm2.oMC.id) { + + sm2.oMC.id = sm2.movieID; + sm2.oMC.className = swfCSS.swfDefault + ' ' + extraClass; + s = null; + oEl = null; + + if (!sm2.useFlashBlock) { + if (sm2.useHighPerformance) { + // on-screen at all times + s = { + position: 'fixed', + width: '8px', + height: '8px', + // >= 6px for flash to run fast, >= 8px to start up under Firefox/win32 in some cases. odd? yes. + bottom: '0px', + left: '0px', + overflow: 'hidden' }; - if(sm2.debugFlash) { - oEmbed.FlashVars = 'debug=1'; - } - if(!sm2.wmode) { - // don't write empty attribute - delete oEmbed.wmode; - } - if(isIE) { - // IE is "special". - oMovie = doc.createElement('div'); - movieHTML = ['', - param('movie', smURL), - param('AllowScriptAccess', sm2.allowScriptAccess), - param('quality', oEmbed.quality), (sm2.wmode ? param('wmode', sm2.wmode) : ''), - param('bgcolor', sm2.bgColor), - param('hasPriority', 'true'), (sm2.debugFlash ? param('FlashVars', oEmbed.FlashVars) : ''), '' - ].join(''); - } else { - oMovie = doc.createElement('embed'); - for(tmp in oEmbed) { - if(oEmbed.hasOwnProperty(tmp)) { - oMovie.setAttribute(tmp, oEmbed[tmp]); - } - } - } - initDebug(); - extraClass = getSWFCSS(); - oTarget = getDocument(); - if(oTarget) { - sm2.oMC = (id(sm2.movieID) || doc.createElement('div')); - if(!sm2.oMC.id) { - sm2.oMC.id = sm2.movieID; - sm2.oMC.className = swfCSS.swfDefault + ' ' + extraClass; - s = null; - oEl = null; - if(!sm2.useFlashBlock) { - if(sm2.useHighPerformance) { - // on-screen at all times - s = { - 'position': 'fixed', - 'width': '8px', - 'height': '8px', - // >= 6px for flash to run fast, >= 8px to start up under Firefox/win32 in some cases. odd? yes. - 'bottom': '0px', - 'left': '0px', - 'overflow': 'hidden' - }; - } else { - // hide off-screen, lower priority - s = { - 'position': 'absolute', - 'width': '6px', - 'height': '6px', - 'top': '-9999px', - 'left': '-9999px' - }; - if(isRTL) { - s.left = Math.abs(parseInt(s.left, 10)) + 'px'; - } - } - } - if(isWebkit) { - // soundcloud-reported render/crash fix, safari 5 - sm2.oMC.style.zIndex = 10000; - } - if(!sm2.debugFlash) { - for(x in s) { - if(s.hasOwnProperty(x)) { - sm2.oMC.style[x] = s[x]; - } - } - } - try { - if(!isIE) { - sm2.oMC.appendChild(oMovie); - } - oTarget.appendChild(sm2.oMC); - if(isIE) { - oEl = sm2.oMC.appendChild(doc.createElement('div')); - oEl.className = swfCSS.swfBox; - oEl.innerHTML = movieHTML; - } - appendSuccess = true; - } catch(e) { - throw new Error(str('domError') + ' \n' + e.toString()); - } - } else { - // SM2 container is already in the document (eg. flashblock use case) - sClass = sm2.oMC.className; - sm2.oMC.className = (sClass ? sClass + ' ' : swfCSS.swfDefault) + (extraClass ? ' ' + extraClass : ''); - sm2.oMC.appendChild(oMovie); - if(isIE) { - oEl = sm2.oMC.appendChild(doc.createElement('div')); - oEl.className = swfCSS.swfBox; - oEl.innerHTML = movieHTML; - } - appendSuccess = true; - } - } - didAppend = true; - initMsg(); - // sm2._wD(sm + ': Trying to load ' + smURL + (!overHTTP && sm2.altURL ? ' (alternate URL)' : ''), 1); - return true; - }; - initMovie = function() { - if(sm2.html5Only) { - createMovie(); - return false; - } - // attempt to get, or create, movie (may already exist) - if(flash) { - return false; - } - if(!sm2.url) { - /** - * Something isn't right - we've reached init, but the soundManager url property has not been set. - * User has not called setup({url: ...}), or has not set soundManager.url (legacy use case) directly before init time. - * Notify and exit. If user calls setup() with a url: property, init will be restarted as in the deferred loading case. - */ - _wDS('noURL'); - return false; - } - // inline markup case - flash = sm2.getMovie(sm2.id); - if(!flash) { - if(!oRemoved) { - // try to create - createMovie(sm2.id, sm2.url); - } else { - // try to re-append removed movie after reboot() - if(!isIE) { - sm2.oMC.appendChild(oRemoved); - } else { - sm2.oMC.innerHTML = oRemovedHTML; - } - oRemoved = null; - didAppend = true; - } - flash = sm2.getMovie(sm2.id); - } - if(typeof sm2.oninitmovie === 'function') { - setTimeout(sm2.oninitmovie, 1); - } - // - flushMessages(); - // - return true; - }; - delayWaitForEI = function() { - setTimeout(waitForEI, 1000); - }; - rebootIntoHTML5 = function() { - // special case: try for a reboot with preferFlash: false, if 100% HTML5 mode is possible and useFlashBlock is not enabled. - window.setTimeout(function() { - complain(smc + 'useFlashBlock is false, 100% HTML5 mode is possible. Rebooting with preferFlash: false...'); - sm2.setup({ - preferFlash: false - }).reboot(); - // if for some reason you want to detect this case, use an ontimeout() callback and look for html5Only and didFlashBlock == true. - sm2.didFlashBlock = true; - sm2.beginDelayedInit(); - }, 1); - }; - waitForEI = function() { - var p, - loadIncomplete = false; - if(!sm2.url) { - // No SWF url to load (noURL case) - exit for now. Will be retried when url is set. - return false; - } - if(waitingForEI) { - return false; - } - waitingForEI = true; - event.remove(window, 'load', delayWaitForEI); - if(hasFlash && tryInitOnFocus && !isFocused) { - // Safari won't load flash in background tabs, only when focused. - _wDS('waitFocus'); - return false; - } - if(!didInit) { - p = sm2.getMoviePercent(); - if(p > 0 && p < 100) { - loadIncomplete = true; - } - } - setTimeout(function() { - p = sm2.getMoviePercent(); - if(loadIncomplete) { - // special case: if movie *partially* loaded, retry until it's 100% before assuming failure. - waitingForEI = false; - sm2._wD(str('waitSWF')); - window.setTimeout(delayWaitForEI, 1); - return false; - } - // - if(!didInit) { - sm2._wD(sm + ': No Flash response within expected time. Likely causes: ' + (p === 0 ? 'SWF load failed, ' : '') + 'Flash blocked or JS-Flash security error.' + (sm2.debugFlash ? ' ' + str('checkSWF') : ''), 2); - if(!overHTTP && p) { - _wDS('localFail', 2); - if(!sm2.debugFlash) { - _wDS('tryDebug', 2); - } - } - if(p === 0) { - // if 0 (not null), probably a 404. - sm2._wD(str('swf404', sm2.url), 1); - } - debugTS('flashtojs', false, ': Timed out' + overHTTP ? ' (Check flash security or flash blockers)' : ' (No plugin/missing SWF?)'); - } - // - // give up / time-out, depending - if(!didInit && okToDisable) { - if(p === null) { - // SWF failed to report load progress. Possibly blocked. - if(sm2.useFlashBlock || sm2.flashLoadTimeout === 0) { - if(sm2.useFlashBlock) { - flashBlockHandler(); - } - _wDS('waitForever'); - } else { - // no custom flash block handling, but SWF has timed out. Will recover if user unblocks / allows SWF load. - if(!sm2.useFlashBlock && canIgnoreFlash) { - rebootIntoHTML5(); - } else { - _wDS('waitForever'); - // fire any regular registered ontimeout() listeners. - processOnEvents({ - type: 'ontimeout', - ignoreInit: true, - error: { - type: 'INIT_FLASHBLOCK' - } - }); - } - } - } else { - // SWF loaded? Shouldn't be a blocking issue, then. - if(sm2.flashLoadTimeout === 0) { - _wDS('waitForever'); - } else { - if(!sm2.useFlashBlock && canIgnoreFlash) { - rebootIntoHTML5(); - } else { - failSafely(true); - } - } - } - } - }, sm2.flashLoadTimeout); - }; - handleFocus = function() { - function cleanup() { - event.remove(window, 'focus', handleFocus); - } - if(isFocused || !tryInitOnFocus) { - // already focused, or not special Safari background tab case - cleanup(); - return true; - } - okToDisable = true; - isFocused = true; - _wDS('gotFocus'); - // allow init to restart - waitingForEI = false; - // kick off ExternalInterface timeout, now that the SWF has started - delayWaitForEI(); - cleanup(); - return true; - }; - flushMessages = function() { - // - // SM2 pre-init debug messages - if(messages.length) { - sm2._wD('SoundManager 2: ' + messages.join(' '), 1); - messages = []; - } - // - }; - showSupport = function() { - // - flushMessages(); - var item, tests = []; - if(sm2.useHTML5Audio && sm2.hasHTML5) { - for(item in sm2.audioFormats) { - if(sm2.audioFormats.hasOwnProperty(item)) { - tests.push(item + ' = ' + sm2.html5[item] + (!sm2.html5[item] && needsFlash && sm2.flash[item] ? ' (using flash)' : (sm2.preferFlash && sm2.flash[item] && needsFlash ? ' (preferring flash)' : (!sm2.html5[item] ? ' (' + (sm2.audioFormats[item].required ? 'required, ' : '') + 'and no flash support)' : '')))); - } - } - sm2._wD('SoundManager 2 HTML5 support: ' + tests.join(', '), 1); - } - // - }; - initComplete = function(bNoDisable) { - if(didInit) { - return false; - } - if(sm2.html5Only) { - // all good. - _wDS('sm2Loaded', 1); - didInit = true; - initUserOnload(); - debugTS('onload', true); - return true; - } - var wasTimeout = (sm2.useFlashBlock && sm2.flashLoadTimeout && !sm2.getMoviePercent()), - result = true, - error; - if(!wasTimeout) { - didInit = true; - } - error = { - type: (!hasFlash && needsFlash ? 'NO_FLASH' : 'INIT_TIMEOUT') + } else { + // hide off-screen, lower priority + s = { + position: 'absolute', + width: '6px', + height: '6px', + top: '-9999px', + left: '-9999px' }; - sm2._wD('SoundManager 2 ' + (disabled ? 'failed to load' : 'loaded') + ' (' + (disabled ? 'Flash security/load error' : 'OK') + ') ' + String.fromCharCode(disabled ? 10006 : 10003), disabled ? 2 : 1); - if(disabled || bNoDisable) { - if(sm2.useFlashBlock && sm2.oMC) { - sm2.oMC.className = getSWFCSS() + ' ' + (sm2.getMoviePercent() === null ? swfCSS.swfTimedout : swfCSS.swfError); - } - processOnEvents({ - type: 'ontimeout', - error: error, - ignoreInit: true - }); - debugTS('onload', false); - catchError(error); - result = false; - } else { - debugTS('onload', true); - } - if(!disabled) { - if(sm2.waitForWindowLoad && !windowLoaded) { - _wDS('waitOnload'); - event.add(window, 'load', initUserOnload); - } else { - // - if(sm2.waitForWindowLoad && windowLoaded) { - _wDS('docLoaded'); - } - // - initUserOnload(); - } - } - return result; - }; - /** - * apply top-level setupOptions object as local properties, eg., this.setupOptions.flashVersion -> this.flashVersion (soundManager.flashVersion) - * this maintains backward compatibility, and allows properties to be defined separately for use by soundManager.setup(). - */ - setProperties = function() { - var i, - o = sm2.setupOptions; - for(i in o) { - if(o.hasOwnProperty(i)) { - // assign local property if not already defined - if(sm2[i] === _undefined) { - sm2[i] = o[i]; - } else if(sm2[i] !== o[i]) { - // legacy support: write manually-assigned property (eg., soundManager.url) back to setupOptions to keep things in sync - sm2.setupOptions[i] = sm2[i]; - } - } + if (isRTL) { + s.left = Math.abs(parseInt(s.left, 10)) + 'px'; } - }; - init = function() { - // called after onload() - if(didInit) { - _wDS('didInit'); - return false; + } + } + + if (isWebkit) { + // soundcloud-reported render/crash fix, safari 5 + sm2.oMC.style.zIndex = 10000; + } + + if (!sm2.debugFlash) { + for (x in s) { + if (s.hasOwnProperty(x)) { + sm2.oMC.style[x] = s[x]; } + } + } + + try { + + if (!isIE) { + sm2.oMC.appendChild(oMovie); + } + + oTarget.appendChild(sm2.oMC); + + if (isIE) { + oEl = sm2.oMC.appendChild(doc.createElement('div')); + oEl.className = swfCSS.swfBox; + oEl.innerHTML = movieHTML; + } + + appendSuccess = true; + + } catch(e) { + + throw new Error(str('domError') + ' \n' + e.toString()); + + } + + } else { + + // SM2 container is already in the document (eg. flashblock use case) + sClass = sm2.oMC.className; + sm2.oMC.className = (sClass ? sClass + ' ' : swfCSS.swfDefault) + (extraClass ? ' ' + extraClass : ''); + sm2.oMC.appendChild(oMovie); + + if (isIE) { + oEl = sm2.oMC.appendChild(doc.createElement('div')); + oEl.className = swfCSS.swfBox; + oEl.innerHTML = movieHTML; + } + + appendSuccess = true; + + } + + } + + didAppend = true; + + initMsg(); + + // sm2._wD(sm + ': Trying to load ' + movieURL + (!overHTTP && sm2.altURL ? ' (alternate URL)' : ''), 1); + + return true; + + }; + + initMovie = function() { + + if (sm2.html5Only) { + createMovie(); + return false; + } + + // attempt to get, or create, movie (may already exist) + if (flash) return false; + + if (!sm2.url) { + + /** + * Something isn't right - we've reached init, but the soundManager url property has not been set. + * User has not called setup({url: ...}), or has not set soundManager.url (legacy use case) directly before init time. + * Notify and exit. If user calls setup() with a url: property, init will be restarted as in the deferred loading case. + */ + + _wDS('noURL'); + return false; + + } + + // inline markup case + flash = sm2.getMovie(sm2.id); + + if (!flash) { + + if (!oRemoved) { + + // try to create + createMovie(sm2.id, sm2.url); + + } else { + + // try to re-append removed movie after reboot() + if (!isIE) { + sm2.oMC.appendChild(oRemoved); + } else { + sm2.oMC.innerHTML = oRemovedHTML; + } + + oRemoved = null; + didAppend = true; + + } + + flash = sm2.getMovie(sm2.id); + + } + + if (typeof sm2.oninitmovie === 'function') { + setTimeout(sm2.oninitmovie, 1); + } + + // + flushMessages(); + // + + return true; + + }; + + delayWaitForEI = function() { + + setTimeout(waitForEI, 1000); + + }; + + rebootIntoHTML5 = function() { + + // special case: try for a reboot with preferFlash: false, if 100% HTML5 mode is possible and useFlashBlock is not enabled. + + window.setTimeout(function() { + + complain(smc + 'useFlashBlock is false, 100% HTML5 mode is possible. Rebooting with preferFlash: false...'); + + sm2.setup({ + preferFlash: false + }).reboot(); + + // if for some reason you want to detect this case, use an ontimeout() callback and look for html5Only and didFlashBlock == true. + sm2.didFlashBlock = true; + + sm2.beginDelayedInit(); + + }, 1); + + }; + + waitForEI = function() { + + var p, + loadIncomplete = false; + + if (!sm2.url) { + // No SWF url to load (noURL case) - exit for now. Will be retried when url is set. + return; + } + + if (waitingForEI) { + return; + } + + waitingForEI = true; + event.remove(window, 'load', delayWaitForEI); + + if (hasFlash && tryInitOnFocus && !isFocused) { + // Safari won't load flash in background tabs, only when focused. + _wDS('waitFocus'); + return; + } + + if (!didInit) { + p = sm2.getMoviePercent(); + if (p > 0 && p < 100) { + loadIncomplete = true; + } + } + + setTimeout(function() { + + p = sm2.getMoviePercent(); + + if (loadIncomplete) { + // special case: if movie *partially* loaded, retry until it's 100% before assuming failure. + waitingForEI = false; + sm2._wD(str('waitSWF')); + window.setTimeout(delayWaitForEI, 1); + return; + } + + // + if (!didInit) { + + sm2._wD(sm + ': No Flash response within expected time. Likely causes: ' + (p === 0 ? 'SWF load failed, ' : '') + 'Flash blocked or JS-Flash security error.' + (sm2.debugFlash ? ' ' + str('checkSWF') : ''), 2); + + if (!overHTTP && p) { + + _wDS('localFail', 2); + + if (!sm2.debugFlash) { + _wDS('tryDebug', 2); + } + + } + + if (p === 0) { + + // if 0 (not null), probably a 404. + sm2._wD(str('swf404', sm2.url), 1); + + } + + debugTS('flashtojs', false, ': Timed out' + (overHTTP ? ' (Check flash security or flash blockers)' : ' (No plugin/missing SWF?)')); + + } + // + + // give up / time-out, depending + + if (!didInit && okToDisable) { + + if (p === null) { + + // SWF failed to report load progress. Possibly blocked. + + if (sm2.useFlashBlock || sm2.flashLoadTimeout === 0) { + + if (sm2.useFlashBlock) { + + flashBlockHandler(); - function cleanup() { - event.remove(window, 'load', sm2.beginDelayedInit); - } - if(sm2.html5Only) { - if(!didInit) { - // we don't need no steenking flash! - cleanup(); - sm2.enabled = true; - initComplete(); - } - return true; - } - // flash path - initMovie(); - try { - // attempt to talk to Flash - flash._externalInterfaceTest(false); - // apply user-specified polling interval, OR, if "high performance" set, faster vs. default polling - // (determines frequency of whileloading/whileplaying callbacks, effectively driving UI framerates) - setPolling(true, (sm2.flashPollingInterval || (sm2.useHighPerformance ? 10 : 50))); - if(!sm2.debugMode) { - // stop the SWF from making debug output calls to JS - flash._disableDebug(); - } - sm2.enabled = true; - debugTS('jstoflash', true); - if(!sm2.html5Only) { - // prevent browser from showing cached page state (or rather, restoring "suspended" page state) via back button, because flash may be dead - // http://www.webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/ - event.add(window, 'unload', doNothing); - } - } catch(e) { - sm2._wD('js/flash exception: ' + e.toString()); - debugTS('jstoflash', false); - catchError({ - type: 'JS_TO_FLASH_EXCEPTION', - fatal: true - }); - // don't disable, for reboot() - failSafely(true); - initComplete(); - return false; - } - initComplete(); - // disconnect events - cleanup(); - return true; - }; - domContentLoaded = function() { - if(didDCLoaded) { - return false; - } - didDCLoaded = true; - // assign top-level soundManager properties eg. soundManager.url - setProperties(); - initDebug(); - /** - * Temporary feature: allow force of HTML5 via URL params: sm2-usehtml5audio=0 or 1 - * Ditto for sm2-preferFlash, too. - */ - // - (function() { - var a = 'sm2-usehtml5audio=', - a2 = 'sm2-preferflash=', - b = null, - b2 = null, - l = wl.toLowerCase(); - if(l.indexOf(a) !== -1) { - b = (l.charAt(l.indexOf(a) + a.length) === '1'); - if(hasConsole) { - console.log((b ? 'Enabling ' : 'Disabling ') + 'useHTML5Audio via URL parameter'); - } - sm2.setup({ - 'useHTML5Audio': b - }); - } - if(l.indexOf(a2) !== -1) { - b2 = (l.charAt(l.indexOf(a2) + a2.length) === '1'); - if(hasConsole) { - console.log((b2 ? 'Enabling ' : 'Disabling ') + 'preferFlash via URL parameter'); - } - sm2.setup({ - 'preferFlash': b2 - }); - } - }()); - // - if(!hasFlash && sm2.hasHTML5) { - sm2._wD('SoundManager 2: No Flash detected' + (!sm2.useHTML5Audio ? ', enabling HTML5.' : '. Trying HTML5-only mode.'), 1); - sm2.setup({ - 'useHTML5Audio': true, - // make sure we aren't preferring flash, either - // TODO: preferFlash should not matter if flash is not installed. Currently, stuff breaks without the below tweak. - 'preferFlash': false - }); - } - testHTML5(); - if(!hasFlash && needsFlash) { - messages.push(strings.needFlash); - // TODO: Fatal here vs. timeout approach, etc. - // hack: fail sooner. - sm2.setup({ - 'flashLoadTimeout': 1 - }); - } - if(doc.removeEventListener) { - doc.removeEventListener('DOMContentLoaded', domContentLoaded, false); - } - initMovie(); - return true; - }; - domContentLoadedIE = function() { - if(doc.readyState === 'complete') { - domContentLoaded(); - doc.detachEvent('onreadystatechange', domContentLoadedIE); - } - return true; - }; - winOnLoad = function() { - // catch edge case of initComplete() firing after window.load() - windowLoaded = true; - // catch case where DOMContentLoaded has been sent, but we're still in doc.readyState = 'interactive' - domContentLoaded(); - event.remove(window, 'load', winOnLoad); - }; - /** - * miscellaneous run-time, pre-init stuff - */ - preInit = function() { - if(mobileHTML5) { - // prefer HTML5 for mobile + tablet-like devices, probably more reliable vs. flash at this point. - // - if(!sm2.setupOptions.useHTML5Audio || sm2.setupOptions.preferFlash) { - // notify that defaults are being changed. - messages.push(strings.mobileUA); - } - // - sm2.setupOptions.useHTML5Audio = true; - sm2.setupOptions.preferFlash = false; - if(is_iDevice || (isAndroid && !ua.match(/android\s2\.3/i))) { - // iOS and Android devices tend to work better with a single audio instance, specifically for chained playback of sounds in sequence. - // common use case: exiting sound onfinish() -> createSound() -> play() - // - messages.push(strings.globalHTML5); - // - if(is_iDevice) { - sm2.ignoreFlash = true; - } - useGlobalHTML5Audio = true; - } } - }; - preInit(); - // sniff up-front - detectFlash(); - // focus and window load, init (primarily flash-driven) - event.add(window, 'focus', handleFocus); - event.add(window, 'load', delayWaitForEI); - event.add(window, 'load', winOnLoad); - if(doc.addEventListener) { - doc.addEventListener('DOMContentLoaded', domContentLoaded, false); - } else if(doc.attachEvent) { - doc.attachEvent('onreadystatechange', domContentLoadedIE); - } else { - // no add/attachevent support - safe to assume no JS -> Flash either - debugTS('onload', false); - catchError({ - type: 'NO_DOM2_EVENTS', - fatal: true + + _wDS('waitForever'); + + } else if (!sm2.useFlashBlock && canIgnoreFlash) { + + // no custom flash block handling, but SWF has timed out. Will recover if user unblocks / allows SWF load. + rebootIntoHTML5(); + + } else { + + _wDS('waitForever'); + + // fire any regular registered ontimeout() listeners. + processOnEvents({ + type: 'ontimeout', + ignoreInit: true, + error: { + type: 'INIT_FLASHBLOCK' + } }); + + } + + } else if (sm2.flashLoadTimeout === 0) { + + // SWF loaded? Shouldn't be a blocking issue, then. + + _wDS('waitForever'); + + } else if (!sm2.useFlashBlock && canIgnoreFlash) { + + rebootIntoHTML5(); + + } else { + + failSafely(true); + + } + + } + + }, sm2.flashLoadTimeout); + + }; + + handleFocus = function() { + + function cleanup() { + event.remove(window, 'focus', handleFocus); + } + + if (isFocused || !tryInitOnFocus) { + // already focused, or not special Safari background tab case + cleanup(); + return true; + } + + okToDisable = true; + isFocused = true; + _wDS('gotFocus'); + + // allow init to restart + waitingForEI = false; + + // kick off ExternalInterface timeout, now that the SWF has started + delayWaitForEI(); + + cleanup(); + return true; + + }; + + flushMessages = function() { + + // + + // SM2 pre-init debug messages + if (messages.length) { + sm2._wD('SoundManager 2: ' + messages.join(' '), 1); + messages = []; + } + + // + + }; + + showSupport = function() { + + // + + flushMessages(); + + var item, tests = []; + + if (sm2.useHTML5Audio && sm2.hasHTML5) { + for (item in sm2.audioFormats) { + if (sm2.audioFormats.hasOwnProperty(item)) { + tests.push(item + ' = ' + sm2.html5[item] + (!sm2.html5[item] && needsFlash && sm2.flash[item] ? ' (using flash)' : (sm2.preferFlash && sm2.flash[item] && needsFlash ? ' (preferring flash)' : (!sm2.html5[item] ? ' (' + (sm2.audioFormats[item].required ? 'required, ' : '') + 'and no flash support)' : '')))); + } + } + sm2._wD('SoundManager 2 HTML5 support: ' + tests.join(', '), 1); + } + + // + + }; + + initComplete = function(bNoDisable) { + + if (didInit) return false; + + if (sm2.html5Only) { + // all good. + _wDS('sm2Loaded', 1); + didInit = true; + initUserOnload(); + debugTS('onload', true); + return true; + } + + var wasTimeout = (sm2.useFlashBlock && sm2.flashLoadTimeout && !sm2.getMoviePercent()), + result = true, + error; + + if (!wasTimeout) { + didInit = true; + } + + error = { + type: (!hasFlash && needsFlash ? 'NO_FLASH' : 'INIT_TIMEOUT') + }; + + sm2._wD('SoundManager 2 ' + (disabled ? 'failed to load' : 'loaded') + ' (' + (disabled ? 'Flash security/load error' : 'OK') + ') ' + String.fromCharCode(disabled ? 10006 : 10003), disabled ? 2 : 1); + + if (disabled || bNoDisable) { + + if (sm2.useFlashBlock && sm2.oMC) { + sm2.oMC.className = getSWFCSS() + ' ' + (sm2.getMoviePercent() === null ? swfCSS.swfTimedout : swfCSS.swfError); + } + + processOnEvents({ + type: 'ontimeout', + error: error, + ignoreInit: true + }); + + debugTS('onload', false); + catchError(error); + + result = false; + + } else { + + debugTS('onload', true); + + } + + if (!disabled) { + + if (sm2.waitForWindowLoad && !windowLoaded) { + + _wDS('waitOnload'); + event.add(window, 'load', initUserOnload); + + } else { + + // + if (sm2.waitForWindowLoad && windowLoaded) { + _wDS('docLoaded'); + } + // + + initUserOnload(); + + } + + } + + return result; + + }; + + /** + * apply top-level setupOptions object as local properties, eg., this.setupOptions.flashVersion -> this.flashVersion (soundManager.flashVersion) + * this maintains backward compatibility, and allows properties to be defined separately for use by soundManager.setup(). + */ + + setProperties = function() { + + var i, + o = sm2.setupOptions; + + for (i in o) { + + if (o.hasOwnProperty(i)) { + + // assign local property if not already defined + + if (sm2[i] === _undefined) { + + sm2[i] = o[i]; + + } else if (sm2[i] !== o[i]) { + + // legacy support: write manually-assigned property (eg., soundManager.url) back to setupOptions to keep things in sync + sm2.setupOptions[i] = sm2[i]; + } - } // SoundManager() - // SM2_DEFER details: http://www.schillmania.com/projects/soundmanager2/doc/getstarted/#lazy-loading - if(window.SM2_DEFER === undefined || !SM2_DEFER) { - soundManager = new SoundManager(); + + } + + } + + }; + + + init = function() { + + // called after onload() + + if (didInit) { + _wDS('didInit'); + return false; + } + + function cleanup() { + event.remove(window, 'load', sm2.beginDelayedInit); + } + + if (sm2.html5Only) { + + if (!didInit) { + // we don't need no steenking flash! + cleanup(); + sm2.enabled = true; + initComplete(); + } + + return true; + + } + + // flash path + initMovie(); + + try { + + // attempt to talk to Flash + flash._externalInterfaceTest(false); + + /** + * Apply user-specified polling interval, OR, if "high performance" set, faster vs. default polling + * (determines frequency of whileloading/whileplaying callbacks, effectively driving UI framerates) + */ + setPolling(true, (sm2.flashPollingInterval || (sm2.useHighPerformance ? 10 : 50))); + + if (!sm2.debugMode) { + // stop the SWF from making debug output calls to JS + flash._disableDebug(); + } + + sm2.enabled = true; + debugTS('jstoflash', true); + + if (!sm2.html5Only) { + // prevent browser from showing cached page state (or rather, restoring "suspended" page state) via back button, because flash may be dead + // http://www.webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/ + event.add(window, 'unload', doNothing); + } + + } catch(e) { + + sm2._wD('js/flash exception: ' + e.toString()); + + debugTS('jstoflash', false); + + catchError({ + type: 'JS_TO_FLASH_EXCEPTION', + fatal: true + }); + + // don't disable, for reboot() + failSafely(true); + + initComplete(); + + return false; + + } + + initComplete(); + + // disconnect events + cleanup(); + + return true; + + }; + + domContentLoaded = function() { + + if (didDCLoaded) return false; + + didDCLoaded = true; + + // assign top-level soundManager properties eg. soundManager.url + setProperties(); + + initDebug(); + + if (!hasFlash && sm2.hasHTML5) { + + sm2._wD('SoundManager 2: No Flash detected' + (!sm2.useHTML5Audio ? ', enabling HTML5.' : '. Trying HTML5-only mode.'), 1); + + sm2.setup({ + useHTML5Audio: true, + // make sure we aren't preferring flash, either + // TODO: preferFlash should not matter if flash is not installed. Currently, stuff breaks without the below tweak. + preferFlash: false + }); + + } + + testHTML5(); + + if (!hasFlash && needsFlash) { + + messages.push(strings.needFlash); + + // TODO: Fatal here vs. timeout approach, etc. + // hack: fail sooner. + sm2.setup({ + flashLoadTimeout: 1 + }); + + } + + if (doc.removeEventListener) { + doc.removeEventListener('DOMContentLoaded', domContentLoaded, false); + } + + initMovie(); + + return true; + + }; + + domContentLoadedIE = function() { + + if (doc.readyState === 'complete') { + domContentLoaded(); + doc.detachEvent('onreadystatechange', domContentLoadedIE); } + + return true; + + }; + + winOnLoad = function() { + + // catch edge case of initComplete() firing after window.load() + windowLoaded = true; + + // catch case where DOMContentLoaded has been sent, but we're still in doc.readyState = 'interactive' + domContentLoaded(); + + event.remove(window, 'load', winOnLoad); + + }; + + // sniff up-front + detectFlash(); + + // focus and window load, init (primarily flash-driven) + event.add(window, 'focus', handleFocus); + event.add(window, 'load', delayWaitForEI); + event.add(window, 'load', winOnLoad); + + if (doc.addEventListener) { + + doc.addEventListener('DOMContentLoaded', domContentLoaded, false); + + } else if (doc.attachEvent) { + + doc.attachEvent('onreadystatechange', domContentLoadedIE); + + } else { + + // no add/attachevent support - safe to assume no JS -> Flash either + debugTS('onload', false); + catchError({ + type: 'NO_DOM2_EVENTS', + fatal: true + }); + + } + +} // SoundManager() + +// SM2_DEFER details: http://www.schillmania.com/projects/soundmanager2/doc/getstarted/#lazy-loading + +if (window.SM2_DEFER === _undefined || !SM2_DEFER) { + soundManager = new SoundManager(); +} + +/** + * SoundManager public interfaces + * ------------------------------ + */ + +if (typeof module === 'object' && module && typeof module.exports === 'object') { + + /** + * commonJS module + */ + + module.exports.SoundManager = SoundManager; + module.exports.soundManager = soundManager; + +} else if (typeof define === 'function' && define.amd) { + + /** + * AMD - requireJS + * basic usage: + * require(["/path/to/soundmanager2.js"], function(SoundManager) { + * SoundManager.getInstance().setup({ + * url: '/swf/', + * onready: function() { ... } + * }) + * }); + * + * SM2_DEFER usage: + * window.SM2_DEFER = true; + * require(["/path/to/soundmanager2.js"], function(SoundManager) { + * SoundManager.getInstance(function() { + * var soundManager = new SoundManager.constructor(); + * soundManager.setup({ + * url: '/swf/', + * ... + * }); + * ... + * soundManager.beginDelayedInit(); + * return soundManager; + * }) + * }); + */ + + define(function() { /** - * SoundManager public interfaces - * ------------------------------ + * Retrieve the global instance of SoundManager. + * If a global instance does not exist it can be created using a callback. + * + * @param {Function} smBuilder Optional: Callback used to create a new SoundManager instance + * @return {SoundManager} The global SoundManager instance */ - if(typeof module === 'object' && module && typeof module.exports === 'object') { - /** - * commonJS module - * note: SM2 requires a window global due to Flash, which makes calls to window.soundManager. - * flash may not always be needed, but this is not known until async init and SM2 may even "reboot" into Flash mode. - */ - window.soundManager = soundManager; - module.exports.SoundManager = SoundManager; - module.exports.soundManager = soundManager; - } else if(typeof define === 'function' && define.amd) { - // AMD - requireJS - define('SoundManager', [], function() { - return { - SoundManager: SoundManager, - soundManager: soundManager - }; - }); - } else { - // standard browser case - window.SoundManager = SoundManager; // constructor - window.soundManager = soundManager; // public API, flash callbacks etc. + function getInstance(smBuilder) { + if (!window.soundManager && smBuilder instanceof Function) { + var instance = smBuilder(SoundManager); + if (instance instanceof SoundManager) { + window.soundManager = instance; + } + } + return window.soundManager; } + return { + constructor: SoundManager, + getInstance: getInstance + }; + }); + +} + +// standard browser case + +// constructor +window.SoundManager = SoundManager; + +/** + * note: SM2 requires a window global due to Flash, which makes calls to window.soundManager. + * Flash may not always be needed, but this is not known until async init and SM2 may even "reboot" into Flash mode. + */ + +// public API, flash callbacks etc. +window.soundManager = soundManager; + }(window)); var ngSoundManager = angular.module('angularSoundManager', []) @@ -4692,6 +6587,9 @@ ngSoundManager.factory('angularPlayer', ['$rootScope', '$log', if ((bootstrapTrack != null) && (isResume !== true)) { var angularPlayerObj = this; var sound = soundManager.getSoundById(trackId); + if (sound == undefined){ + return; + } sound.setVolume(volume); bootstrapTrack(sound, this.currentTrackData(), function(){ soundManager.play(trackId); @@ -5310,6 +7208,7 @@ ngSoundManager.directive('playPauseToggle', ['angularPlayer', restrict: "EA", link: function(scope, element, attrs) { scope.$on('music:isPlaying', function(event, data) { + return; //update html if (data) { if(typeof attrs.pause != 'undefined') { diff --git a/app/listen1_chrome_extension/js/vendor/angular-translate-loader-static-files.min.js b/app/listen1_chrome_extension/js/vendor/angular-translate-loader-static-files.min.js new file mode 100644 index 0000000..9fabf23 --- /dev/null +++ b/app/listen1_chrome_extension/js/vendor/angular-translate-loader-static-files.min.js @@ -0,0 +1,6 @@ +/*! + * angular-translate - v2.18.1 - 2018-05-19 + * + * Copyright (c) 2018 The angular-translate team, Pascal Precht; Licensed MIT + */ +!function(e,i){"function"==typeof define&&define.amd?define([],function(){return i()}):"object"==typeof module&&module.exports?module.exports=i():i()}(0,function(){function e(n,a){"use strict";return function(r){if(!(r&&(angular.isArray(r.files)||angular.isString(r.prefix)&&angular.isString(r.suffix))))throw new Error("Couldn't load static files, no files and prefix or suffix specified!");r.files||(r.files=[{prefix:r.prefix,suffix:r.suffix}]);for(var e=function(e){if(!e||!angular.isString(e.prefix)||!angular.isString(e.suffix))throw new Error("Couldn't load static file, no prefix or suffix specified!");var i=[e.prefix,r.key,e.suffix].join("");return angular.isObject(r.fileMap)&&r.fileMap[i]&&(i=r.fileMap[i]),a(angular.extend({url:i,method:"GET"},r.$http)).then(function(e){return e.data},function(){return n.reject(r.key)})},i=[],t=r.files.length,f=0;f
");return e.text(t),e.html()},i=function(t){if(!n)throw new Error("pascalprecht.translate.$translateSanitization: Error cannot find $sanitize service. Either include the ngSanitize module (https://docs.angularjs.org/api/ngSanitize) or use a sanitization strategy which does not depend on $sanitize, such as 'escape'.");return n(t)},s=function(t){if(!a)throw new Error("pascalprecht.translate.$translateSanitization: Error cannot find $sce service.");return a.trustAsHtml(t)},o=function(t,n,a){if(angular.isDate(t))return t;if(angular.isObject(t)){var r=angular.isArray(t)?[]:{};if(a){if(-1c)return"...";var d=b.$$hashKey,g;if(I(a)){g=0;for(var f=a.length;g").append(a).html();try{return a[0].nodeType===Oa?N(b):b.match(/^(<[^>]+>)/)[1].replace(/^<([\w-]+)/,function(a,b){return"<"+N(b)})}catch(d){return N(b)}}function Tc(a){try{return decodeURIComponent(a)}catch(b){}}function dc(a){var b={};p((a||"").split("&"),function(a){var c,e,f;a&&(e=a=a.replace(/\+/g, -"%20"),c=a.indexOf("="),-1!==c&&(e=a.substring(0,c),f=a.substring(c+1)),e=Tc(e),t(e)&&(f=t(f)?Tc(f):!0,ra.call(b,e)?I(b[e])?b[e].push(f):b[e]=[b[e],f]:b[e]=f))});return b}function ec(a){var b=[];p(a,function(a,c){I(a)?p(a,function(a){b.push(ia(c,!0)+(!0===a?"":"="+ia(a,!0)))}):b.push(ia(c,!0)+(!0===a?"":"="+ia(a,!0)))});return b.length?b.join("&"):""}function gb(a){return ia(a,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function ia(a,b){return encodeURIComponent(a).replace(/%40/gi, -"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%3B/gi,";").replace(/%20/g,b?"%20":"+")}function ve(a,b){var d,c,e=Ha.length;for(c=0;c protocol indicates an extension, document.location.href does not match."))}function Uc(a,b,d){E(d)||(d={});d=Q({strictDi:!1},d);var c=function(){a=A(a);if(a.injector()){var c=a[0]===u.document?"document":Aa(a);throw qa("btstrpd",c.replace(//,">"));}b=b||[];b.unshift(["$provide",function(b){b.value("$rootElement",a)}]);d.debugInfoEnabled&&b.push(["$compileProvider",function(a){a.debugInfoEnabled(!0)}]); -b.unshift("ng");c=hb(b,d.strictDi);c.invoke(["$rootScope","$rootElement","$compile","$injector",function(a,b,c,d){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return c},e=/^NG_ENABLE_DEBUG_INFO!/,f=/^NG_DEFER_BOOTSTRAP!/;u&&e.test(u.name)&&(d.debugInfoEnabled=!0,u.name=u.name.replace(e,""));if(u&&!f.test(u.name))return c();u.name=u.name.replace(f,"");$.resumeBootstrap=function(a){p(a,function(a){b.push(a)});return c()};B($.resumeDeferredBootstrap)&&$.resumeDeferredBootstrap()}function ye(){u.name= -"NG_ENABLE_DEBUG_INFO!"+u.name;u.location.reload()}function ze(a){a=$.element(a).injector();if(!a)throw qa("test");return a.get("$$testability")}function Vc(a,b){b=b||"_";return a.replace(Ae,function(a,c){return(c?b:"")+a.toLowerCase()})}function Be(){var a;if(!Wc){var b=sb();(la=w(b)?u.jQuery:b?u[b]:void 0)&&la.fn.on?(A=la,Q(la.fn,{scope:Sa.scope,isolateScope:Sa.isolateScope,controller:Sa.controller,injector:Sa.injector,inheritedData:Sa.inheritedData}),a=la.cleanData,la.cleanData=function(b){for(var c, -e=0,f;null!=(f=b[e]);e++)(c=la._data(f,"events"))&&c.$destroy&&la(f).triggerHandler("$destroy");a(b)}):A=V;$.element=A;Wc=!0}}function ib(a,b,d){if(!a)throw qa("areq",b||"?",d||"required");return a}function tb(a,b,d){d&&I(a)&&(a=a[a.length-1]);ib(B(a),b,"not a function, got "+(a&&"object"===typeof a?a.constructor.name||"Object":typeof a));return a}function Ia(a,b){if("hasOwnProperty"===a)throw qa("badname",b);}function Xc(a,b,d){if(!b)return a;b=b.split(".");for(var c,e=a,f=b.length,g=0;g")+c[2];for(c=c[0];c--;)d=d.lastChild;f=eb(f,d.childNodes);d=e.firstChild;d.textContent=""}else f.push(b.createTextNode(a));e.textContent="";e.innerHTML="";p(f,function(a){e.appendChild(a)});return e}function V(a){if(a instanceof V)return a;var b;D(a)&&(a=R(a),b=!0);if(!(this instanceof V)){if(b&&"<"!==a.charAt(0))throw jc("nosel");return new V(a)}if(b){b=u.document;var d;a=(d=fg.exec(a))?[b.createElement(d[1])]:(d=fd(a,b))?d.childNodes: -[];kc(this,a)}else B(a)?gd(a):kc(this,a)}function lc(a){return a.cloneNode(!0)}function zb(a,b){!b&&hc(a)&&A.cleanData([a]);a.querySelectorAll&&A.cleanData(a.querySelectorAll("*"))}function hd(a,b,d,c){if(t(c))throw jc("offargs");var e=(c=Ab(a))&&c.events,f=c&&c.handle;if(f)if(b){var g=function(b){var c=e[b];t(d)&&db(c||[],d);t(d)&&c&&0l&&this.remove(q.key);return b}},get:function(a){if(l";b=Ba.firstChild.attributes;var d=b[0];b.removeNamedItem(d.name);d.value=c;a.attributes.setNamedItem(d)}function na(a,b){try{a.addClass(b)}catch(c){}}function ca(a,b,c,d,e){a instanceof A||(a=A(a));var g=Va(a,b,a,c,d,e);ca.$$addScopeClass(a); -var f=null;return function(b,c,d){if(!a)throw ba("multilink");ib(b,"scope");e&&e.needsNewScope&&(b=b.$parent.$new());d=d||{};var h=d.parentBoundTranscludeFn,k=d.transcludeControllers;d=d.futureParentElement;h&&h.$$boundTransclude&&(h=h.$$boundTransclude);f||(f=(d=d&&d[0])?"foreignobject"!==za(d)&&ha.call(d).match(/SVG/)?"svg":"html":"html");d="html"!==f?A(ja(f,A("
").append(a).html())):c?Sa.clone.call(a):a;if(k)for(var l in k)d.data("$"+l+"Controller",k[l].instance);ca.$$addScopeInfo(d,b);c&& -c(d,b);g&&g(b,d,d,h);c||(a=g=null);return d}}function Va(a,b,c,d,e,g){function f(a,c,d,e){var g,k,l,m,q,n,H;if(s)for(H=Array(c.length),m=0;mx.priority)break;if(u=x.scope)x.templateUrl||(E(u)?(aa("new/isolated scope",K||s,x,F),K=x):aa("new/isolated scope",K,x,F)),s=s||x;z=x.name;if(!t&&(x.replace&&(x.templateUrl||x.template)||x.transclude&&!x.$$tlb)){for(u=Da+1;t=a[u++];)if(t.transclude&&!t.$$tlb||t.replace&&(t.templateUrl||t.template)){Jb=!0;break}t=!0}!x.templateUrl&&x.controller&&(J=J||T(),aa("'"+z+"' controller",J[z],x,F),J[z]=x);if(u=x.transclude)if(S=!0, -x.$$tlb||(aa("transclusion",y,x,F),y=x),"element"===u)ta=!0,n=x.priority,O=F,F=d.$$element=A(ca.$$createComment(z,d[z])),b=F[0],la(g,ya.call(O,0),b),O[0].$$parentNode=O[0].parentNode,r=W(Jb,O,e,n,f&&f.name,{nonTlbTranscludeDirective:y});else{var na=T();if(E(u)){O=[];var Va=T(),Ma=T();p(u,function(a,b){var c="?"===a.charAt(0);a=c?a.substring(1):a;Va[a]=b;na[b]=null;Ma[b]=c});p(F.contents(),function(a){var b=Va[Ea(za(a))];b?(Ma[b]=!0,na[b]=na[b]||[],na[b].push(a)):O.push(a)});p(Ma,function(a,b){if(!a)throw ba("reqslot", -b);});for(var N in na)na[N]&&(na[N]=W(Jb,na[N],e))}else O=A(lc(b)).contents();F.empty();r=W(Jb,O,e,void 0,void 0,{needsNewScope:x.$$isolateScope||x.$$newScope});r.$$slots=na}if(x.template)if(L=!0,aa("template",v,x,F),v=x,u=B(x.template)?x.template(F,d):x.template,u=Ia(u),x.replace){f=x;O=ic.test(u)?qd(ja(x.templateNamespace,R(u))):[];b=O[0];if(1!==O.length||1!==b.nodeType)throw ba("tplrt",z,"");la(g,F,b);C={$attr:{}};u=M(b,[],C);var pc=a.splice(Da+1,a.length-(Da+1));(K||s)&&Z(u,K,s);a=a.concat(u).concat(pc); -ea(d,C);C=a.length}else F.html(u);if(x.templateUrl)L=!0,aa("template",v,x,F),v=x,x.replace&&(f=x),q=ia(a.splice(Da,a.length-Da),F,d,g,S&&r,h,k,{controllerDirectives:J,newScopeDirective:s!==x&&s,newIsolateScopeDirective:K,templateDirective:v,nonTlbTranscludeDirective:y}),C=a.length;else if(x.compile)try{P=x.compile(F,d,r);var U=x.$$originalDirective||x;B(P)?m(null,Ra(U,P),Ua,D):P&&m(Ra(U,P.pre),Ra(U,P.post),Ua,D)}catch($){c($,Aa(F))}x.terminal&&(q.terminal=!0,n=Math.max(n,x.priority))}q.scope=s&&!0=== -s.scope;q.transcludeOnThisElement=S;q.templateOnThisElement=L;q.transclude=r;l.hasElementTranscludeDirective=ta;return q}function X(a,b,c,d){var e;if(D(b)){var g=b.match(l);b=b.substring(g[0].length);var f=g[1]||g[3],g="?"===g[2];"^^"===f?c=c.parent():e=(e=d&&d[b])&&e.instance;if(!e){var h="$"+b+"Controller";e=f?c.inheritedData(h):c.data(h)}if(!e&&!g)throw ba("ctreq",b,a);}else if(I(b))for(e=[],f=0,g=b.length;fc.priority)&&-1!==c.restrict.indexOf(e)){k&&(c=Zb(c,{$$start:k,$$end:l}));if(!c.$$bindings){var s=m=c,H=c.name,J={isolateScope:null,bindToController:null};E(s.scope)&&(!0===s.bindToController?(J.bindToController=d(s.scope,H,!0),J.isolateScope={}):J.isolateScope=d(s.scope,H,!1));E(s.bindToController)&&(J.bindToController=d(s.bindToController,H,!0));if(J.bindToController&&!s.controller)throw ba("noctrl",H);m=m.$$bindings=J;E(m.isolateScope)&&(c.$$isolateBindings=m.isolateScope)}b.push(c); -m=c}}return m}function $(b){if(f.hasOwnProperty(b))for(var c=a.get(b+"Directive"),d=0,e=c.length;d"+b+"";return c.childNodes[0].childNodes;default:return b}}function va(a,b){if("srcdoc"===b)return x.HTML;var c=za(a);if("src"===b||"ngSrc"===b){if(-1===["img","video","audio","source","track"].indexOf(c))return x.RESOURCE_URL}else if("xlinkHref"===b||"form"===c&&"action"===b||"link"===c&&"href"===b)return x.RESOURCE_URL}function xa(a,c,d,e,g){var f=va(a,e),k=h[e]||g,l=b(d,!g,f,k);if(l){if("multiple"===e&&"select"===za(a))throw ba("selmulti", -Aa(a));if(m.test(e))throw ba("nodomevents");c.push({priority:100,compile:function(){return{pre:function(a,c,g){c=g.$$observers||(g.$$observers=T());var h=g[e];h!==d&&(l=h&&b(h,!0,f,k),d=h);l&&(g[e]=l(a),(c[e]||(c[e]=[])).$$inter=!0,(g.$$observers&&g.$$observers[e].$$scope||a).$watch(l,function(a,b){"class"===e&&a!==b?g.$updateClass(a,b):g.$set(e,a)}))}}}})}}function la(a,b,c){var d=b[0],e=b.length,g=d.parentNode,f,h;if(a)for(f=0,h=a.length;f=b)return a;for(;b--;){var d=a[b];(8===d.nodeType||d.nodeType===Oa&&""===d.nodeValue.trim())&&ug.call(a,b,1)}return a}function sg(a,b){if(b&&D(b))return b;if(D(a)){var d=td.exec(a);if(d)return d[3]}}function yf(){var a={},b=!1;this.has=function(b){return a.hasOwnProperty(b)};this.register=function(b, -c){Ia(b,"controller");E(b)?Q(a,b):a[b]=c};this.allowGlobals=function(){b=!0};this.$get=["$injector","$window",function(d,c){function e(a,b,c,d){if(!a||!E(a.$scope))throw M("$controller")("noscp",d,b);a.$scope[b]=c}return function(f,g,k,h){var l,m,n;k=!0===k;h&&D(h)&&(n=h);if(D(f)){h=f.match(td);if(!h)throw ud("ctrlfmt",f);m=h[1];n=n||h[3];f=a.hasOwnProperty(m)?a[m]:Xc(g.$scope,m,!0)||(b?Xc(c,m,!0):void 0);if(!f)throw ud("ctrlreg",m);tb(f,m,!0)}if(k)return k=(I(f)?f[f.length-1]:f).prototype,l=Object.create(k|| -null),n&&e(g,n,l,m||f.name),Q(function(){var a=d.invoke(f,l,g,m);a!==l&&(E(a)||B(a))&&(l=a,n&&e(g,n,l,m||f.name));return l},{instance:l,identifier:n});l=d.instantiate(f,g,m);n&&e(g,n,l,m||f.name);return l}}]}function zf(){this.$get=["$window",function(a){return A(a.document)}]}function Af(){this.$get=["$document","$rootScope",function(a,b){function d(){e=c.hidden}var c=a[0],e=c&&c.hidden;a.on("visibilitychange",d);b.$on("$destroy",function(){a.off("visibilitychange",d)});return function(){return e}}]} -function Bf(){this.$get=["$log",function(a){return function(b,d){a.error.apply(a,arguments)}}]}function rc(a){return E(a)?ea(a)?a.toISOString():fb(a):a}function Gf(){this.$get=function(){return function(a){if(!a)return"";var b=[];Oc(a,function(a,c){null===a||w(a)||B(a)||(I(a)?p(a,function(a){b.push(ia(c)+"="+ia(rc(a)))}):b.push(ia(c)+"="+ia(rc(a))))});return b.join("&")}}}function Hf(){this.$get=function(){return function(a){function b(a,e,f){null===a||w(a)||(I(a)?p(a,function(a,c){b(a,e+"["+(E(a)? -c:"")+"]")}):E(a)&&!ea(a)?Oc(a,function(a,c){b(a,e+(f?"":"[")+c+(f?"":"]"))}):d.push(ia(e)+"="+ia(rc(a))))}if(!a)return"";var d=[];b(a,"",!0);return d.join("&")}}}function sc(a,b){if(D(a)){var d=a.replace(vg,"").trim();if(d){var c=b("Content-Type"),c=c&&0===c.indexOf(vd),e;(e=c)||(e=(e=d.match(wg))&&xg[e[0]].test(d));if(e)try{a=Rc(d)}catch(f){if(!c)return a;throw Lb("baddata",a,f);}}}return a}function wd(a){var b=T(),d;D(a)?p(a.split("\n"),function(a){d=a.indexOf(":");var e=N(R(a.substr(0,d)));a= -R(a.substr(d+1));e&&(b[e]=b[e]?b[e]+", "+a:a)}):E(a)&&p(a,function(a,d){var f=N(d),g=R(a);f&&(b[f]=b[f]?b[f]+", "+g:g)});return b}function xd(a){var b;return function(d){b||(b=wd(a));return d?(d=b[N(d)],void 0===d&&(d=null),d):b}}function yd(a,b,d,c){if(B(c))return c(a,b,d);p(c,function(c){a=c(a,b,d)});return a}function Ff(){var a=this.defaults={transformResponse:[sc],transformRequest:[function(a){return E(a)&&"[object File]"!==ha.call(a)&&"[object Blob]"!==ha.call(a)&&"[object FormData]"!==ha.call(a)? -fb(a):a}],headers:{common:{Accept:"application/json, text/plain, */*"},post:ja(tc),put:ja(tc),patch:ja(tc)},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",paramSerializer:"$httpParamSerializer",jsonpCallbackParam:"callback"},b=!1;this.useApplyAsync=function(a){return t(a)?(b=!!a,this):b};var d=this.interceptors=[];this.$get=["$browser","$httpBackend","$$cookieReader","$cacheFactory","$rootScope","$q","$injector","$sce",function(c,e,f,g,k,h,l,m){function n(b){function d(a,b){for(var c=0, -e=b.length;ca?b:h.reject(b)}if(!E(b))throw M("$http")("badreq",b);if(!D(m.valueOf(b.url)))throw M("$http")("badreq",b.url);var f=Q({method:"get",transformRequest:a.transformRequest,transformResponse:a.transformResponse,paramSerializer:a.paramSerializer, -jsonpCallbackParam:a.jsonpCallbackParam},b);f.headers=function(b){var c=a.headers,d=Q({},b.headers),g,f,h,c=Q({},c.common,c[N(b.method)]);a:for(g in c){f=N(g);for(h in d)if(N(h)===f)continue a;d[g]=c[g]}return e(d,ja(b))}(b);f.method=vb(f.method);f.paramSerializer=D(f.paramSerializer)?l.get(f.paramSerializer):f.paramSerializer;c.$$incOutstandingRequestCount();var k=[],n=[];b=h.resolve(f);p(v,function(a){(a.request||a.requestError)&&k.unshift(a.request,a.requestError);(a.response||a.responseError)&& -n.push(a.response,a.responseError)});b=d(b,k);b=b.then(function(b){var c=b.headers,d=yd(b.data,xd(c),void 0,b.transformRequest);w(d)&&p(c,function(a,b){"content-type"===N(b)&&delete c[b]});w(b.withCredentials)&&!w(a.withCredentials)&&(b.withCredentials=a.withCredentials);return q(b,d).then(g,g)});b=d(b,n);return b=b.finally(function(){c.$$completeOutstandingRequest(C)})}function q(c,d){function g(a){if(a){var c={};p(a,function(a,d){c[d]=function(c){function d(){a(c)}b?k.$applyAsync(d):k.$$phase?d(): -k.$apply(d)}});return c}}function l(a,c,d,e,g){function f(){q(c,a,d,e,g)}S&&(200<=a&&300>a?S.put(P,[a,c,wd(d),e,g]):S.remove(P));b?k.$applyAsync(f):(f(),k.$$phase||k.$apply())}function q(a,b,d,e,g){b=-1<=b?b:0;(200<=b&&300>b?K.resolve:K.reject)({data:a,status:b,headers:xd(d),config:c,statusText:e,xhrStatus:g})}function H(a){q(a.data,a.status,ja(a.headers()),a.statusText,a.xhrStatus)}function v(){var a=n.pendingRequests.indexOf(c);-1!==a&&n.pendingRequests.splice(a,1)}var K=h.defer(),F=K.promise,S, -x,O=c.headers,r="jsonp"===N(c.method),P=c.url;r?P=m.getTrustedResourceUrl(P):D(P)||(P=m.valueOf(P));P=G(P,c.paramSerializer(c.params));r&&(P=L(P,c.jsonpCallbackParam));n.pendingRequests.push(c);F.then(v,v);!c.cache&&!a.cache||!1===c.cache||"GET"!==c.method&&"JSONP"!==c.method||(S=E(c.cache)?c.cache:E(a.cache)?a.cache:z);S&&(x=S.get(P),t(x)?x&&B(x.then)?x.then(H,H):I(x)?q(x[1],x[0],ja(x[2]),x[3],x[4]):q(x,200,{},"OK","complete"):S.put(P,F));w(x)&&((x=zd(c.url)?f()[c.xsrfCookieName||a.xsrfCookieName]: -void 0)&&(O[c.xsrfHeaderName||a.xsrfHeaderName]=x),e(c.method,P,d,l,O,c.timeout,c.withCredentials,c.responseType,g(c.eventHandlers),g(c.uploadEventHandlers)));return F}function G(a,b){0=l&&(r.resolve(v),z(ma.$$intervalId),delete g[ma.$$intervalId]);s||a.$apply()},h);g[ma.$$intervalId]= -r;return ma}var g={};f.cancel=function(a){return a&&a.$$intervalId in g?(g[a.$$intervalId].promise.$$state.pur=!0,g[a.$$intervalId].reject("canceled"),b.clearInterval(a.$$intervalId),delete g[a.$$intervalId],!0):!1};return f}]}function uc(a){a=a.split("/");for(var b=a.length;b--;)a[b]=gb(a[b].replace(/%2F/g,"/"));return a.join("/")}function Ad(a,b){var d=ua(a);b.$$protocol=d.protocol;b.$$host=d.hostname;b.$$port=Z(d.port)||zg[d.protocol]||null}function Bd(a,b,d){if(Ag.test(a))throw lb("badpath",a); -var c="/"!==a.charAt(0);c&&(a="/"+a);a=ua(a);for(var c=(c&&"/"===a.pathname.charAt(0)?a.pathname.substring(1):a.pathname).split("/"),e=c.length;e--;)c[e]=decodeURIComponent(c[e]),d&&(c[e]=c[e].replace(/\//g,"%2F"));d=c.join("/");b.$$path=d;b.$$search=dc(a.search);b.$$hash=decodeURIComponent(a.hash);b.$$path&&"/"!==b.$$path.charAt(0)&&(b.$$path="/"+b.$$path)}function vc(a,b){return a.slice(0,b.length)===b}function va(a,b){if(vc(b,a))return b.substr(a.length)}function La(a){var b=a.indexOf("#");return-1=== -b?a:a.substr(0,b)}function mb(a){return a.replace(/(#.+)|#$/,"$1")}function wc(a,b,d){this.$$html5=!0;d=d||"";Ad(a,this);this.$$parse=function(a){var d=va(b,a);if(!D(d))throw lb("ipthprfx",a,b);Bd(d,this,!0);this.$$path||(this.$$path="/");this.$$compose()};this.$$compose=function(){var a=ec(this.$$search),d=this.$$hash?"#"+gb(this.$$hash):"";this.$$url=uc(this.$$path)+(a?"?"+a:"")+d;this.$$absUrl=b+this.$$url.substr(1);this.$$urlUpdatedByLocation=!0};this.$$parseLinkUrl=function(c,e){if(e&&"#"=== -e[0])return this.hash(e.slice(1)),!0;var f,g;t(f=va(a,c))?(g=f,g=d&&t(f=va(d,f))?b+(va("/",f)||f):a+g):t(f=va(b,c))?g=b+f:b===c+"/"&&(g=b);g&&this.$$parse(g);return!!g}}function xc(a,b,d){Ad(a,this);this.$$parse=function(c){var e=va(a,c)||va(b,c),f;w(e)||"#"!==e.charAt(0)?this.$$html5?f=e:(f="",w(e)&&(a=c,this.replace())):(f=va(d,e),w(f)&&(f=e));Bd(f,this,!1);c=this.$$path;var e=a,g=/^\/[A-Z]:(\/.*)/;vc(f,e)&&(f=f.replace(e,""));g.exec(f)||(c=(f=g.exec(c))?f[1]:c);this.$$path=c;this.$$compose()}; -this.$$compose=function(){var b=ec(this.$$search),e=this.$$hash?"#"+gb(this.$$hash):"";this.$$url=uc(this.$$path)+(b?"?"+b:"")+e;this.$$absUrl=a+(this.$$url?d+this.$$url:"");this.$$urlUpdatedByLocation=!0};this.$$parseLinkUrl=function(b,d){return La(a)===La(b)?(this.$$parse(b),!0):!1}}function Cd(a,b,d){this.$$html5=!0;xc.apply(this,arguments);this.$$parseLinkUrl=function(c,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;a===La(c)?f=c:(g=va(b,c))?f=a+d+g:b===c+"/"&&(f=b);f&&this.$$parse(f); -return!!f};this.$$compose=function(){var b=ec(this.$$search),e=this.$$hash?"#"+gb(this.$$hash):"";this.$$url=uc(this.$$path)+(b?"?"+b:"")+e;this.$$absUrl=a+d+this.$$url;this.$$urlUpdatedByLocation=!0}}function Mb(a){return function(){return this[a]}}function Dd(a,b){return function(d){if(w(d))return this[a];this[a]=b(d);this.$$compose();return this}}function Lf(){var a="!",b={enabled:!1,requireBase:!0,rewriteLinks:!0};this.hashPrefix=function(b){return t(b)?(a=b,this):a};this.html5Mode=function(a){if(Na(a))return b.enabled= -a,this;if(E(a)){Na(a.enabled)&&(b.enabled=a.enabled);Na(a.requireBase)&&(b.requireBase=a.requireBase);if(Na(a.rewriteLinks)||D(a.rewriteLinks))b.rewriteLinks=a.rewriteLinks;return this}return b};this.$get=["$rootScope","$browser","$sniffer","$rootElement","$window",function(d,c,e,f,g){function k(a,b,d){var e=l.url(),g=l.$$state;try{c.url(a,b,d),l.$$state=c.state()}catch(f){throw l.url(e),l.$$state=g,f;}}function h(a,b){d.$broadcast("$locationChangeSuccess",l.absUrl(),a,l.$$state,b)}var l,m;m=c.baseHref(); -var n=c.url(),q;if(b.enabled){if(!m&&b.requireBase)throw lb("nobase");q=n.substring(0,n.indexOf("/",n.indexOf("//")+2))+(m||"/");m=e.history?wc:Cd}else q=La(n),m=xc;var G=q.substr(0,La(q).lastIndexOf("/")+1);l=new m(q,G,"#"+a);l.$$parseLinkUrl(n,n);l.$$state=c.state();var p=/^\s*(javascript|mailto):/i;f.on("click",function(a){var e=b.rewriteLinks;if(e&&!a.ctrlKey&&!a.metaKey&&!a.shiftKey&&2!==a.which&&2!==a.button){for(var h=A(a.target);"a"!==za(h[0]);)if(h[0]===f[0]||!(h=h.parent())[0])return;if(!D(e)|| -!w(h.attr(e))){var e=h.prop("href"),k=h.attr("href")||h.attr("xlink:href");E(e)&&"[object SVGAnimatedString]"===e.toString()&&(e=ua(e.animVal).href);p.test(e)||!e||h.attr("target")||a.isDefaultPrevented()||!l.$$parseLinkUrl(e,k)||(a.preventDefault(),l.absUrl()!==c.url()&&(d.$apply(),g.angular["ff-684208-preventDefault"]=!0))}}});mb(l.absUrl())!==mb(n)&&c.url(l.absUrl(),!0);var r=!0;c.onUrlChange(function(a,b){vc(a,G)?(d.$evalAsync(function(){var c=l.absUrl(),e=l.$$state,g;a=mb(a);l.$$parse(a);l.$$state= -b;g=d.$broadcast("$locationChangeStart",a,c,b,e).defaultPrevented;l.absUrl()===a&&(g?(l.$$parse(c),l.$$state=e,k(c,!1,e)):(r=!1,h(c,e)))}),d.$$phase||d.$digest()):g.location.href=a});d.$watch(function(){if(r||l.$$urlUpdatedByLocation){l.$$urlUpdatedByLocation=!1;var a=mb(c.url()),b=mb(l.absUrl()),g=c.state(),f=l.$$replace,m=a!==b||l.$$html5&&e.history&&g!==l.$$state;if(r||m)r=!1,d.$evalAsync(function(){var b=l.absUrl(),c=d.$broadcast("$locationChangeStart",b,a,l.$$state,g).defaultPrevented;l.absUrl()=== -b&&(c?(l.$$parse(a),l.$$state=g):(m&&k(b,f,g===l.$$state?null:l.$$state),h(a,g)))})}l.$$replace=!1});return l}]}function Mf(){var a=!0,b=this;this.debugEnabled=function(b){return t(b)?(a=b,this):a};this.$get=["$window",function(d){function c(a){ac(a)&&(a.stack&&f?a=a.message&&-1===a.stack.indexOf(a.message)?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function e(a){var b=d.console||{},e=b[a]||b.log||C;return function(){var a=[];p(arguments, -function(b){a.push(c(b))});return Function.prototype.apply.call(e,b,a)}}var f=Ca||/\bEdge\//.test(d.navigator&&d.navigator.userAgent);return{log:e("log"),info:e("info"),warn:e("warn"),error:e("error"),debug:function(){var c=e("debug");return function(){a&&c.apply(b,arguments)}}()}}]}function Bg(a){return a+""}function Cg(a,b){return"undefined"!==typeof a?a:b}function Ed(a,b){return"undefined"===typeof a?b:"undefined"===typeof b?a:a+b}function Dg(a,b){switch(a.type){case r.MemberExpression:if(a.computed)return!1; -break;case r.UnaryExpression:return 1;case r.BinaryExpression:return"+"!==a.operator?1:!1;case r.CallExpression:return!1}return void 0===b?Fd:b}function W(a,b,d){var c,e,f=a.isPure=Dg(a,d);switch(a.type){case r.Program:c=!0;p(a.body,function(a){W(a.expression,b,f);c=c&&a.expression.constant});a.constant=c;break;case r.Literal:a.constant=!0;a.toWatch=[];break;case r.UnaryExpression:W(a.argument,b,f);a.constant=a.argument.constant;a.toWatch=a.argument.toWatch;break;case r.BinaryExpression:W(a.left, -b,f);W(a.right,b,f);a.constant=a.left.constant&&a.right.constant;a.toWatch=a.left.toWatch.concat(a.right.toWatch);break;case r.LogicalExpression:W(a.left,b,f);W(a.right,b,f);a.constant=a.left.constant&&a.right.constant;a.toWatch=a.constant?[]:[a];break;case r.ConditionalExpression:W(a.test,b,f);W(a.alternate,b,f);W(a.consequent,b,f);a.constant=a.test.constant&&a.alternate.constant&&a.consequent.constant;a.toWatch=a.constant?[]:[a];break;case r.Identifier:a.constant=!1;a.toWatch=[a];break;case r.MemberExpression:W(a.object, -b,f);a.computed&&W(a.property,b,f);a.constant=a.object.constant&&(!a.computed||a.property.constant);a.toWatch=a.constant?[]:[a];break;case r.CallExpression:c=d=a.filter?!b(a.callee.name).$stateful:!1;e=[];p(a.arguments,function(a){W(a,b,f);c=c&&a.constant;e.push.apply(e,a.toWatch)});a.constant=c;a.toWatch=d?e:[a];break;case r.AssignmentExpression:W(a.left,b,f);W(a.right,b,f);a.constant=a.left.constant&&a.right.constant;a.toWatch=[a];break;case r.ArrayExpression:c=!0;e=[];p(a.elements,function(a){W(a, -b,f);c=c&&a.constant;e.push.apply(e,a.toWatch)});a.constant=c;a.toWatch=e;break;case r.ObjectExpression:c=!0;e=[];p(a.properties,function(a){W(a.value,b,f);c=c&&a.value.constant;e.push.apply(e,a.value.toWatch);a.computed&&(W(a.key,b,!1),c=c&&a.key.constant,e.push.apply(e,a.key.toWatch))});a.constant=c;a.toWatch=e;break;case r.ThisExpression:a.constant=!1;a.toWatch=[];break;case r.LocalsExpression:a.constant=!1,a.toWatch=[]}}function Gd(a){if(1===a.length){a=a[0].expression;var b=a.toWatch;return 1!== -b.length?b:b[0]!==a?b:void 0}}function Hd(a){return a.type===r.Identifier||a.type===r.MemberExpression}function Id(a){if(1===a.body.length&&Hd(a.body[0].expression))return{type:r.AssignmentExpression,left:a.body[0].expression,right:{type:r.NGValueParameter},operator:"="}}function Jd(a){this.$filter=a}function Kd(a){this.$filter=a}function yc(a,b,d){this.ast=new r(a,d);this.astCompiler=d.csp?new Kd(b):new Jd(b)}function zc(a){return B(a.valueOf)?a.valueOf():Eg.call(a)}function Nf(){var a=T(),b={"true":!0, -"false":!1,"null":null,undefined:void 0},d,c;this.addLiteral=function(a,c){b[a]=c};this.setIdentifierFns=function(a,b){d=a;c=b;return this};this.$get=["$filter",function(e){function f(a,b,c){return null==a||null==b?a===b:"object"!==typeof a||(a=zc(a),"object"!==typeof a||c)?a===b||a!==a&&b!==b:!1}function g(a,b,c,d,e){var g=d.inputs,h;if(1===g.length){var k=f,g=g[0];return a.$watch(function(a){var b=g(a);f(b,k,g.isPure)||(h=d(a,void 0,void 0,[b]),k=b&&zc(b));return h},b,c,e)}for(var l=[],m=[],n=0, -p=g.length;n=c.$$state.status&&e&&e.length&&a(function(){for(var a,c,g=0,f=e.length;ga)for(b in l++,f)ra.call(e,b)||(p--,delete f[b])}else f!==e&&(f=e,l++);return l}}c.$stateful=!0;var d=this,e,f,h,k=1G&&(w=4-G,v[w]||(v[w]=[]),v[w].push({msg:B(a.exp)?"fn: "+(a.exp.name||a.exp.toString()): -a.exp,newVal:g,oldVal:h}));else if(a===c){p=!1;break a}}catch(E){f(E)}if(!(q=y.$$watchersCount&&y.$$childHead||y!==this&&y.$$nextSibling))for(;y!==this&&!(q=y.$$nextSibling);)y=y.$parent}while(y=q);if((p||t.length)&&!G--)throw s.$$phase=null,d("infdig",b,v);}while(p||t.length);for(s.$$phase=null;JCa)throw wa("iequirks");var c=ja(oa);c.isEnabled=function(){return a};c.trustAs= -d.trustAs;c.getTrusted=d.getTrusted;c.valueOf=d.valueOf;a||(c.trustAs=c.getTrusted=function(a,b){return b},c.valueOf=bb);c.parseAs=function(a,d){var e=b(d);return e.literal&&e.constant?e:b(d,function(b){return c.getTrusted(a,b)})};var e=c.parseAs,f=c.getTrusted,g=c.trustAs;p(oa,function(a,b){var d=N(b);c[("parse_as_"+d).replace(Bc,xb)]=function(b){return e(a,b)};c[("get_trusted_"+d).replace(Bc,xb)]=function(b){return f(a,b)};c[("trust_as_"+d).replace(Bc,xb)]=function(b){return g(a,b)}});return c}]} -function Tf(){this.$get=["$window","$document",function(a,b){var d={},c=!((!a.nw||!a.nw.process)&&a.chrome&&(a.chrome.app&&a.chrome.app.runtime||!a.chrome.app&&a.chrome.runtime&&a.chrome.runtime.id))&&a.history&&a.history.pushState,e=Z((/android (\d+)/.exec(N((a.navigator||{}).userAgent))||[])[1]),f=/Boxee/i.test((a.navigator||{}).userAgent),g=b[0]||{},k=g.body&&g.body.style,h=!1,l=!1;k&&(h=!!("transition"in k||"webkitTransition"in k),l=!!("animation"in k||"webkitAnimation"in k));return{history:!(!c|| -4>e||f),hasEvent:function(a){if("input"===a&&Ca)return!1;if(w(d[a])){var b=g.createElement("div");d[a]="on"+a in b}return d[a]},csp:Ja(),transitions:h,animations:l,android:e}}]}function Vf(){var a;this.httpOptions=function(b){return b?(a=b,this):a};this.$get=["$exceptionHandler","$templateCache","$http","$q","$sce",function(b,d,c,e,f){function g(k,h){g.totalPendingRequests++;if(!D(k)||w(d.get(k)))k=f.getTrustedResourceUrl(k);var l=c.defaults&&c.defaults.transformResponse;I(l)?l=l.filter(function(a){return a!== -sc}):l===sc&&(l=null);return c.get(k,Q({cache:d,transformResponse:l},a)).finally(function(){g.totalPendingRequests--}).then(function(a){d.put(k,a.data);return a.data},function(a){h||(a=Gg("tpload",k,a.status,a.statusText),b(a));return e.reject(a)})}g.totalPendingRequests=0;return g}]}function Wf(){this.$get=["$rootScope","$browser","$location",function(a,b,d){return{findBindings:function(a,b,d){a=a.getElementsByClassName("ng-binding");var g=[];p(a,function(a){var c=$.element(a).data("$binding");c&& -p(c,function(c){d?(new RegExp("(^|\\s)"+Md(b)+"(\\s|\\||$)")).test(c)&&g.push(a):-1!==c.indexOf(b)&&g.push(a)})});return g},findModels:function(a,b,d){for(var g=["ng-","data-ng-","ng\\:"],k=0;kc&&(c=e),c+=+a.slice(e+1),a=a.substring(0,e)):0>c&&(c=a.length);for(e=0;a.charAt(e)===Dc;e++);if(e===(g=a.length))d=[0],c=1;else{for(g--;a.charAt(g)===Dc;)g--;c-=e;d=[];for(f=0;e<=g;e++,f++)d[f]=+a.charAt(e)}c>Wd&&(d=d.splice(0,Wd-1),b=c-1,c=1);return{d:d,e:b,i:c}}function Og(a,b,d,c){var e=a.d,f=e.length-a.i;b=w(b)?Math.min(Math.max(d,f),c):+b;d=b+a.i;c=e[d];if(0d-1){for(c=0;c>d;c--)e.unshift(0),a.i++;e.unshift(1);a.i++}else e[d-1]++;for(;fk;)h.unshift(0),k++;0=b.lgSize&&k.unshift(h.splice(-b.lgSize,h.length).join(""));h.length>b.gSize;)k.unshift(h.splice(-b.gSize,h.length).join(""));h.length&&k.unshift(h.join(""));h=k.join(d);f.length&&(h+=c+f.join(""));e&&(h+="e+"+e)}return 0>a&&!g?b.negPre+h+b.negSuf:b.posPre+h+b.posSuf}function Nb(a,b,d,c){var e="";if(0>a||c&&0>=a)c?a=-a+1:(a=-a,e="-");for(a=""+a;a.length< -b;)a=Dc+a;d&&(a=a.substr(a.length-b));return e+a}function da(a,b,d,c,e){d=d||0;return function(f){f=f["get"+a]();if(0-d)f+=d;0===f&&-12===d&&(f=12);return Nb(f,b,c,e)}}function nb(a,b,d){return function(c,e){var f=c["get"+a](),g=vb((d?"STANDALONE":"")+(b?"SHORT":"")+a);return e[g][f]}}function Xd(a){var b=(new Date(a,0,1)).getDay();return new Date(a,0,(4>=b?5:12)-b)}function Yd(a){return function(b){var d=Xd(b.getFullYear());b=+new Date(b.getFullYear(),b.getMonth(),b.getDate()+(4-b.getDay()))- -+d;b=1+Math.round(b/6048E5);return Nb(b,a)}}function Ec(a,b){return 0>=a.getFullYear()?b.ERAS[0]:b.ERAS[1]}function Rd(a){function b(a){var b;if(b=a.match(d)){a=new Date(0);var f=0,g=0,k=b[8]?a.setUTCFullYear:a.setFullYear,h=b[8]?a.setUTCHours:a.setHours;b[9]&&(f=Z(b[9]+b[10]),g=Z(b[9]+b[11]));k.call(a,Z(b[1]),Z(b[2])-1,Z(b[3]));f=Z(b[4]||0)-f;g=Z(b[5]||0)-g;k=Z(b[6]||0);b=Math.round(1E3*parseFloat("0."+(b[7]||0)));h.call(a,f,g,k,b)}return a}var d=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/; -return function(c,d,f){var g="",k=[],h,l;d=d||"mediumDate";d=a.DATETIME_FORMATS[d]||d;D(c)&&(c=Pg.test(c)?Z(c):b(c));Y(c)&&(c=new Date(c));if(!ea(c)||!isFinite(c.getTime()))return c;for(;d;)(l=Qg.exec(d))?(k=eb(k,l,1),d=k.pop()):(k.push(d),d=null);var m=c.getTimezoneOffset();f&&(m=Sc(f,m),c=cc(c,f,!0));p(k,function(b){h=Rg[b];g+=h?h(c,a.DATETIME_FORMATS,m):"''"===b?"'":b.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function Ig(){return function(a,b){w(b)&&(b=2);return fb(a,b)}}function Jg(){return function(a, -b,d){b=Infinity===Math.abs(Number(b))?Number(b):Z(b);if(U(b))return a;Y(a)&&(a=a.toString());if(!xa(a))return a;d=!d||isNaN(d)?0:Z(d);d=0>d?Math.max(0,a.length+d):d;return 0<=b?Fc(a,d,d+b):0===d?Fc(a,b,a.length):Fc(a,Math.max(0,d+b),d)}}function Fc(a,b,d){return D(a)?a.slice(b,d):ya.call(a,b,d)}function Td(a){function b(b){return b.map(function(b){var c=1,d=bb;if(B(b))d=b;else if(D(b)){if("+"===b.charAt(0)||"-"===b.charAt(0))c="-"===b.charAt(0)?-1:1,b=b.substring(1);if(""!==b&&(d=a(b),d.constant))var e= -d(),d=function(a){return a[e]}}return{get:d,descending:c}})}function d(a){switch(typeof a){case "number":case "boolean":case "string":return!0;default:return!1}}function c(a,b){var c=0,d=a.type,h=b.type;if(d===h){var h=a.value,l=b.value;"string"===d?(h=h.toLowerCase(),l=l.toLowerCase()):"object"===d&&(E(h)&&(h=a.index),E(l)&&(l=b.index));h!==l&&(c=hb||37<=b&&40>=b||m(a,this,this.value)});if(e.hasEvent("paste"))b.on("paste cut",m)}b.on("change",l);if(ce[g]&&c.$$hasNativeValidators&&g===d.type)b.on("keydown wheel mousedown",function(a){if(!h){var b=this.validity,c=b.badInput,d=b.typeMismatch;h=f.defer(function(){h=null;b.badInput===c&&b.typeMismatch=== -d||l(a)})}});c.$render=function(){var a=c.$isEmpty(c.$viewValue)?"":c.$viewValue;b.val()!==a&&b.val(a)}}function Qb(a,b){return function(d,c){var e,f;if(ea(d))return d;if(D(d)){'"'===d.charAt(0)&&'"'===d.charAt(d.length-1)&&(d=d.substring(1,d.length-1));if(Sg.test(d))return new Date(d);a.lastIndex=0;if(e=a.exec(d))return e.shift(),f=c?{yyyy:c.getFullYear(),MM:c.getMonth()+1,dd:c.getDate(),HH:c.getHours(),mm:c.getMinutes(),ss:c.getSeconds(),sss:c.getMilliseconds()/1E3}:{yyyy:1970,MM:1,dd:1,HH:0,mm:0, -ss:0,sss:0},p(e,function(a,c){c=z};g.$observe("min",function(a){z=q(a);k.$validate()})}if(t(g.max)||g.ngMax){var v;k.$validators.max=function(a){return!n(a)||w(v)||d(a)<=v};g.$observe("max",function(a){v=q(a);k.$validate()})}}}function Hc(a,b,d,c){(c.$$hasNativeValidators=E(b[0].validity))&&c.$parsers.push(function(a){var c=b.prop("validity")||{}; -return c.badInput||c.typeMismatch?void 0:a})}function de(a){a.$$parserName="number";a.$parsers.push(function(b){if(a.$isEmpty(b))return null;if(Tg.test(b))return parseFloat(b)});a.$formatters.push(function(b){if(!a.$isEmpty(b)){if(!Y(b))throw qb("numfmt",b);b=b.toString()}return b})}function Xa(a){t(a)&&!Y(a)&&(a=parseFloat(a));return U(a)?void 0:a}function Ic(a){var b=a.toString(),d=b.indexOf(".");return-1===d?-1a&&(a=/e-(\d+)$/.exec(b))?Number(a[1]):0:b.length-d-1}function ee(a,b,d){a=Number(a); -var c=(a|0)!==a,e=(b|0)!==b,f=(d|0)!==d;if(c||e||f){var g=c?Ic(a):0,k=e?Ic(b):0,h=f?Ic(d):0,g=Math.max(g,k,h),g=Math.pow(10,g);a*=g;b*=g;d*=g;c&&(a=Math.round(a));e&&(b=Math.round(b));f&&(d=Math.round(d))}return 0===(a-b)%d}function fe(a,b,d,c,e){if(t(c)){a=a(c);if(!a.constant)throw qb("constexpr",d,c);return a(b)}return e}function Jc(a,b){function d(a,b){if(!a||!a.length)return[];if(!b||!b.length)return a;var c=[],d=0;a:for(;d(?:<\/\1>|)$/,ic=/<|&#?\w+;/,dg=/<([\w:-]+)/,eg=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,aa={option:[1,'"],thead:[1, -"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};aa.optgroup=aa.option;aa.tbody=aa.tfoot=aa.colgroup=aa.caption=aa.thead;aa.th=aa.td;var lg=u.Node.prototype.contains||function(a){return!!(this.compareDocumentPosition(a)&16)},Sa=V.prototype={ready:gd,toString:function(){var a=[];p(this,function(b){a.push(""+b)});return"["+a.join(", ")+"]"},eq:function(a){return 0<= -a?A(this[a]):A(this[this.length+a])},length:0,push:Wg,sort:[].sort,splice:[].splice},Hb={};p("multiple selected checked disabled readOnly required open".split(" "),function(a){Hb[N(a)]=a});var ld={};p("input select option textarea button form details".split(" "),function(a){ld[a]=!0});var sd={ngMinlength:"minlength",ngMaxlength:"maxlength",ngMin:"min",ngMax:"max",ngPattern:"pattern",ngStep:"step"};p({data:nc,removeData:mc,hasData:function(a){for(var b in jb[a.ng339])return!0;return!1},cleanData:function(a){for(var b= -0,d=a.length;b/,og=/^[^(]*\(\s*([^)]*)\)/m,Zg=/,/,$g=/^\s*(_?)(\S+?)\1\s*$/,mg= -/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,Ba=M("$injector");hb.$$annotate=function(a,b,d){var c;if("function"===typeof a){if(!(c=a.$inject)){c=[];if(a.length){if(b)throw D(d)&&d||(d=a.name||pg(a)),Ba("strictdi",d);b=nd(a);p(b[1].split(Zg),function(a){a.replace($g,function(a,b,d){c.push(d)})})}a.$inject=c}}else I(a)?(b=a.length-1,tb(a[b],"fn"),c=a.slice(0,b)):tb(a,"fn",!0);return c};var he=M("$animate"),sf=function(){this.$get=C},tf=function(){var a=new Ib,b=[];this.$get=["$$AnimateRunner","$rootScope",function(d, -c){function e(a,b,c){var d=!1;b&&(b=D(b)?b.split(" "):I(b)?b:[],p(b,function(b){b&&(d=!0,a[b]=c)}));return d}function f(){p(b,function(b){var c=a.get(b);if(c){var d=qg(b.attr("class")),e="",f="";p(c,function(a,b){a!==!!d[b]&&(a?e+=(e.length?" ":"")+b:f+=(f.length?" ":"")+b)});p(b,function(a){e&&Eb(a,e);f&&Db(a,f)});a.delete(b)}});b.length=0}return{enabled:C,on:C,off:C,pin:C,push:function(g,k,h,l){l&&l();h=h||{};h.from&&g.css(h.from);h.to&&g.css(h.to);if(h.addClass||h.removeClass)if(k=h.addClass,l= -h.removeClass,h=a.get(g)||{},k=e(h,k,!0),l=e(h,l,!1),k||l)a.set(g,h),b.push(g),1===b.length&&c.$$postDigest(f);g=new d;g.complete();return g}}}]},qf=["$provide",function(a){var b=this,d=null,c=null;this.$$registeredAnimations=Object.create(null);this.register=function(c,d){if(c&&"."!==c.charAt(0))throw he("notcsel",c);var g=c+"-animation";b.$$registeredAnimations[c.substr(1)]=g;a.factory(g,d)};this.customFilter=function(a){1===arguments.length&&(c=B(a)?a:null);return c};this.classNameFilter=function(a){if(1=== -arguments.length&&(d=a instanceof RegExp?a:null)&&/[(\s|\/)]ng-animate[(\s|\/)]/.test(d.toString()))throw d=null,he("nongcls","ng-animate");return d};this.$get=["$$animateQueue",function(a){function b(a,c,d){if(d){var e;a:{for(e=0;e <= >= && || ! = |".split(" "),function(a){Tb[a]=!0});var ch={n:"\n",f:"\f",r:"\r",t:"\t",v:"\v","'":"'",'"':'"'},Ac=function(a){this.options=a};Ac.prototype={constructor:Ac,lex:function(a){this.text=a;this.index=0;for(this.tokens=[];this.index=a&&"string"===typeof a},isWhitespace:function(a){return" "===a||"\r"===a||"\t"===a||"\n"===a||"\v"===a||"\u00a0"===a},isIdentifierStart:function(a){return this.options.isIdentifierStart?this.options.isIdentifierStart(a,this.codePointAt(a)):this.isValidIdentifierStart(a)},isValidIdentifierStart:function(a){return"a"<=a&&"z">=a||"A"<=a&&"Z">=a||"_"===a||"$"===a},isIdentifierContinue:function(a){return this.options.isIdentifierContinue?this.options.isIdentifierContinue(a, -this.codePointAt(a)):this.isValidIdentifierContinue(a)},isValidIdentifierContinue:function(a,b){return this.isValidIdentifierStart(a,b)||this.isNumber(a)},codePointAt:function(a){return 1===a.length?a.charCodeAt(0):(a.charCodeAt(0)<<10)+a.charCodeAt(1)-56613888},peekMultichar:function(){var a=this.text.charAt(this.index),b=this.peek();if(!b)return a;var d=a.charCodeAt(0),c=b.charCodeAt(0);return 55296<=d&&56319>=d&&56320<=c&&57343>=c?a+b:a},isExpOperator:function(a){return"-"===a||"+"===a||this.isNumber(a)}, -throwError:function(a,b,d){d=d||this.index;b=t(b)?"s "+b+"-"+this.index+" ["+this.text.substring(b,d)+"]":" "+d;throw Ya("lexerr",a,b,this.text);},readNumber:function(){for(var a="",b=this.index;this.index","<=",">=");)a={type:r.BinaryExpression,operator:b.text,left:a,right:this.additive()};return a},additive:function(){for(var a=this.multiplicative(),b;b=this.expect("+","-");)a={type:r.BinaryExpression,operator:b.text,left:a,right:this.multiplicative()};return a},multiplicative:function(){for(var a=this.unary(),b;b=this.expect("*","/","%");)a={type:r.BinaryExpression,operator:b.text,left:a,right:this.unary()};return a},unary:function(){var a;return(a=this.expect("+", -"-","!"))?{type:r.UnaryExpression,operator:a.text,prefix:!0,argument:this.unary()}:this.primary()},primary:function(){var a;this.expect("(")?(a=this.filterChain(),this.consume(")")):this.expect("[")?a=this.arrayDeclaration():this.expect("{")?a=this.object():this.selfReferential.hasOwnProperty(this.peek().text)?a=pa(this.selfReferential[this.consume().text]):this.options.literals.hasOwnProperty(this.peek().text)?a={type:r.Literal,value:this.options.literals[this.consume().text]}:this.peek().identifier? -a=this.identifier():this.peek().constant?a=this.constant():this.throwError("not a primary expression",this.peek());for(var b;b=this.expect("(","[",".");)"("===b.text?(a={type:r.CallExpression,callee:a,arguments:this.parseArguments()},this.consume(")")):"["===b.text?(a={type:r.MemberExpression,object:a,property:this.expression(),computed:!0},this.consume("]")):"."===b.text?a={type:r.MemberExpression,object:a,property:this.identifier(),computed:!1}:this.throwError("IMPOSSIBLE");return a},filter:function(a){a= -[a];for(var b={type:r.CallExpression,callee:this.identifier(),arguments:a,filter:!0};this.expect(":");)a.push(this.expression());return b},parseArguments:function(){var a=[];if(")"!==this.peekToken().text){do a.push(this.filterChain());while(this.expect(","))}return a},identifier:function(){var a=this.consume();a.identifier||this.throwError("is not a valid identifier",a);return{type:r.Identifier,name:a.text}},constant:function(){return{type:r.Literal,value:this.consume().value}},arrayDeclaration:function(){var a= -[];if("]"!==this.peekToken().text){do{if(this.peek("]"))break;a.push(this.expression())}while(this.expect(","))}this.consume("]");return{type:r.ArrayExpression,elements:a}},object:function(){var a=[],b;if("}"!==this.peekToken().text){do{if(this.peek("}"))break;b={type:r.Property,kind:"init"};this.peek().constant?(b.key=this.constant(),b.computed=!1,this.consume(":"),b.value=this.expression()):this.peek().identifier?(b.key=this.identifier(),b.computed=!1,this.peek(":")?(this.consume(":"),b.value=this.expression()): -b.value=b.key):this.peek("[")?(this.consume("["),b.key=this.expression(),this.consume("]"),b.computed=!0,this.consume(":"),b.value=this.expression()):this.throwError("invalid key",this.peek());a.push(b)}while(this.expect(","))}this.consume("}");return{type:r.ObjectExpression,properties:a}},throwError:function(a,b){throw Ya("syntax",b.text,a,b.index+1,this.text,this.text.substring(b.index));},consume:function(a){if(0===this.tokens.length)throw Ya("ueoe",this.text);var b=this.expect(a);b||this.throwError("is unexpected, expecting ["+ -a+"]",this.peek());return b},peekToken:function(){if(0===this.tokens.length)throw Ya("ueoe",this.text);return this.tokens[0]},peek:function(a,b,d,c){return this.peekAhead(0,a,b,d,c)},peekAhead:function(a,b,d,c,e){if(this.tokens.length>a){a=this.tokens[a];var f=a.text;if(f===b||f===d||f===c||f===e||!(b||d||c||e))return a}return!1},expect:function(a,b,d,c){return(a=this.peek(a,b,d,c))?(this.tokens.shift(),a):!1},selfReferential:{"this":{type:r.ThisExpression},$locals:{type:r.LocalsExpression}}};var Fd= -2;Jd.prototype={compile:function(a){var b=this;this.state={nextId:0,filters:{},fn:{vars:[],body:[],own:{}},assign:{vars:[],body:[],own:{}},inputs:[]};W(a,b.$filter);var d="",c;this.stage="assign";if(c=Id(a))this.state.computing="assign",d=this.nextId(),this.recurse(c,d),this.return_(d),d="fn.assign="+this.generateFunction("assign","s,v,l");c=Gd(a.body);b.stage="inputs";p(c,function(a,c){var d="fn"+c;b.state[d]={vars:[],body:[],own:{}};b.state.computing=d;var k=b.nextId();b.recurse(a,k);b.return_(k); -b.state.inputs.push({name:d,isPure:a.isPure});a.watchId=c});this.state.computing="fn";this.stage="main";this.recurse(a);a='"'+this.USE+" "+this.STRICT+'";\n'+this.filterPrefix()+"var fn="+this.generateFunction("fn","s,l,a,i")+d+this.watchFns()+"return fn;";a=(new Function("$filter","getStringValue","ifDefined","plus",a))(this.$filter,Bg,Cg,Ed);this.state=this.stage=void 0;return a},USE:"use",STRICT:"strict",watchFns:function(){var a=[],b=this.state.inputs,d=this;p(b,function(b){a.push("var "+b.name+ -"="+d.generateFunction(b.name,"s"));b.isPure&&a.push(b.name,".isPure="+JSON.stringify(b.isPure)+";")});b.length&&a.push("fn.inputs=["+b.map(function(a){return a.name}).join(",")+"];");return a.join("")},generateFunction:function(a,b){return"function("+b+"){"+this.varsPrefix(a)+this.body(a)+"};"},filterPrefix:function(){var a=[],b=this;p(this.state.filters,function(d,c){a.push(d+"=$filter("+b.escape(c)+")")});return a.length?"var "+a.join(",")+";":""},varsPrefix:function(a){return this.state[a].vars.length? -"var "+this.state[a].vars.join(",")+";":""},body:function(a){return this.state[a].body.join("")},recurse:function(a,b,d,c,e,f){var g,k,h=this,l,m,n;c=c||C;if(!f&&t(a.watchId))b=b||this.nextId(),this.if_("i",this.lazyAssign(b,this.computedMember("i",a.watchId)),this.lazyRecurse(a,b,d,c,e,!0));else switch(a.type){case r.Program:p(a.body,function(b,c){h.recurse(b.expression,void 0,void 0,function(a){k=a});c!==a.body.length-1?h.current().body.push(k,";"):h.return_(k)});break;case r.Literal:m=this.escape(a.value); -this.assign(b,m);c(b||m);break;case r.UnaryExpression:this.recurse(a.argument,void 0,void 0,function(a){k=a});m=a.operator+"("+this.ifDefined(k,0)+")";this.assign(b,m);c(m);break;case r.BinaryExpression:this.recurse(a.left,void 0,void 0,function(a){g=a});this.recurse(a.right,void 0,void 0,function(a){k=a});m="+"===a.operator?this.plus(g,k):"-"===a.operator?this.ifDefined(g,0)+a.operator+this.ifDefined(k,0):"("+g+")"+a.operator+"("+k+")";this.assign(b,m);c(m);break;case r.LogicalExpression:b=b||this.nextId(); -h.recurse(a.left,b);h.if_("&&"===a.operator?b:h.not(b),h.lazyRecurse(a.right,b));c(b);break;case r.ConditionalExpression:b=b||this.nextId();h.recurse(a.test,b);h.if_(b,h.lazyRecurse(a.alternate,b),h.lazyRecurse(a.consequent,b));c(b);break;case r.Identifier:b=b||this.nextId();d&&(d.context="inputs"===h.stage?"s":this.assign(this.nextId(),this.getHasOwnProperty("l",a.name)+"?l:s"),d.computed=!1,d.name=a.name);h.if_("inputs"===h.stage||h.not(h.getHasOwnProperty("l",a.name)),function(){h.if_("inputs"=== -h.stage||"s",function(){e&&1!==e&&h.if_(h.isNull(h.nonComputedMember("s",a.name)),h.lazyAssign(h.nonComputedMember("s",a.name),"{}"));h.assign(b,h.nonComputedMember("s",a.name))})},b&&h.lazyAssign(b,h.nonComputedMember("l",a.name)));c(b);break;case r.MemberExpression:g=d&&(d.context=this.nextId())||this.nextId();b=b||this.nextId();h.recurse(a.object,g,void 0,function(){h.if_(h.notNull(g),function(){a.computed?(k=h.nextId(),h.recurse(a.property,k),h.getStringValue(k),e&&1!==e&&h.if_(h.not(h.computedMember(g, -k)),h.lazyAssign(h.computedMember(g,k),"{}")),m=h.computedMember(g,k),h.assign(b,m),d&&(d.computed=!0,d.name=k)):(e&&1!==e&&h.if_(h.isNull(h.nonComputedMember(g,a.property.name)),h.lazyAssign(h.nonComputedMember(g,a.property.name),"{}")),m=h.nonComputedMember(g,a.property.name),h.assign(b,m),d&&(d.computed=!1,d.name=a.property.name))},function(){h.assign(b,"undefined")});c(b)},!!e);break;case r.CallExpression:b=b||this.nextId();a.filter?(k=h.filter(a.callee.name),l=[],p(a.arguments,function(a){var b= -h.nextId();h.recurse(a,b);l.push(b)}),m=k+"("+l.join(",")+")",h.assign(b,m),c(b)):(k=h.nextId(),g={},l=[],h.recurse(a.callee,k,g,function(){h.if_(h.notNull(k),function(){p(a.arguments,function(b){h.recurse(b,a.constant?void 0:h.nextId(),void 0,function(a){l.push(a)})});m=g.name?h.member(g.context,g.name,g.computed)+"("+l.join(",")+")":k+"("+l.join(",")+")";h.assign(b,m)},function(){h.assign(b,"undefined")});c(b)}));break;case r.AssignmentExpression:k=this.nextId();g={};this.recurse(a.left,void 0, -g,function(){h.if_(h.notNull(g.context),function(){h.recurse(a.right,k);m=h.member(g.context,g.name,g.computed)+a.operator+k;h.assign(b,m);c(b||m)})},1);break;case r.ArrayExpression:l=[];p(a.elements,function(b){h.recurse(b,a.constant?void 0:h.nextId(),void 0,function(a){l.push(a)})});m="["+l.join(",")+"]";this.assign(b,m);c(b||m);break;case r.ObjectExpression:l=[];n=!1;p(a.properties,function(a){a.computed&&(n=!0)});n?(b=b||this.nextId(),this.assign(b,"{}"),p(a.properties,function(a){a.computed? -(g=h.nextId(),h.recurse(a.key,g)):g=a.key.type===r.Identifier?a.key.name:""+a.key.value;k=h.nextId();h.recurse(a.value,k);h.assign(h.member(b,g,a.computed),k)})):(p(a.properties,function(b){h.recurse(b.value,a.constant?void 0:h.nextId(),void 0,function(a){l.push(h.escape(b.key.type===r.Identifier?b.key.name:""+b.key.value)+":"+a)})}),m="{"+l.join(",")+"}",this.assign(b,m));c(b||m);break;case r.ThisExpression:this.assign(b,"s");c(b||"s");break;case r.LocalsExpression:this.assign(b,"l");c(b||"l");break; -case r.NGValueParameter:this.assign(b,"v"),c(b||"v")}},getHasOwnProperty:function(a,b){var d=a+"."+b,c=this.current().own;c.hasOwnProperty(d)||(c[d]=this.nextId(!1,a+"&&("+this.escape(b)+" in "+a+")"));return c[d]},assign:function(a,b){if(a)return this.current().body.push(a,"=",b,";"),a},filter:function(a){this.state.filters.hasOwnProperty(a)||(this.state.filters[a]=this.nextId(!0));return this.state.filters[a]},ifDefined:function(a,b){return"ifDefined("+a+","+this.escape(b)+")"},plus:function(a, -b){return"plus("+a+","+b+")"},return_:function(a){this.current().body.push("return ",a,";")},if_:function(a,b,d){if(!0===a)b();else{var c=this.current().body;c.push("if(",a,"){");b();c.push("}");d&&(c.push("else{"),d(),c.push("}"))}},not:function(a){return"!("+a+")"},isNull:function(a){return a+"==null"},notNull:function(a){return a+"!=null"},nonComputedMember:function(a,b){var d=/[^$_a-zA-Z0-9]/g;return/^[$_a-zA-Z][$_a-zA-Z0-9]*$/.test(b)?a+"."+b:a+'["'+b.replace(d,this.stringEscapeFn)+'"]'},computedMember:function(a, -b){return a+"["+b+"]"},member:function(a,b,d){return d?this.computedMember(a,b):this.nonComputedMember(a,b)},getStringValue:function(a){this.assign(a,"getStringValue("+a+")")},lazyRecurse:function(a,b,d,c,e,f){var g=this;return function(){g.recurse(a,b,d,c,e,f)}},lazyAssign:function(a,b){var d=this;return function(){d.assign(a,b)}},stringEscapeRegex:/[^ a-zA-Z0-9]/g,stringEscapeFn:function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)},escape:function(a){if(D(a))return"'"+a.replace(this.stringEscapeRegex, -this.stringEscapeFn)+"'";if(Y(a))return a.toString();if(!0===a)return"true";if(!1===a)return"false";if(null===a)return"null";if("undefined"===typeof a)return"undefined";throw Ya("esc");},nextId:function(a,b){var d="v"+this.state.nextId++;a||this.current().vars.push(d+(b?"="+b:""));return d},current:function(){return this.state[this.state.computing]}};Kd.prototype={compile:function(a){var b=this;W(a,b.$filter);var d,c;if(d=Id(a))c=this.recurse(d);d=Gd(a.body);var e;d&&(e=[],p(d,function(a,c){var d= -b.recurse(a);d.isPure=a.isPure;a.input=d;e.push(d);a.watchId=c}));var f=[];p(a.body,function(a){f.push(b.recurse(a.expression))});a=0===a.body.length?C:1===a.body.length?f[0]:function(a,b){var c;p(f,function(d){c=d(a,b)});return c};c&&(a.assign=function(a,b,d){return c(a,d,b)});e&&(a.inputs=e);return a},recurse:function(a,b,d){var c,e,f=this,g;if(a.input)return this.inputs(a.input,a.watchId);switch(a.type){case r.Literal:return this.value(a.value,b);case r.UnaryExpression:return e=this.recurse(a.argument), -this["unary"+a.operator](e,b);case r.BinaryExpression:return c=this.recurse(a.left),e=this.recurse(a.right),this["binary"+a.operator](c,e,b);case r.LogicalExpression:return c=this.recurse(a.left),e=this.recurse(a.right),this["binary"+a.operator](c,e,b);case r.ConditionalExpression:return this["ternary?:"](this.recurse(a.test),this.recurse(a.alternate),this.recurse(a.consequent),b);case r.Identifier:return f.identifier(a.name,b,d);case r.MemberExpression:return c=this.recurse(a.object,!1,!!d),a.computed|| -(e=a.property.name),a.computed&&(e=this.recurse(a.property)),a.computed?this.computedMember(c,e,b,d):this.nonComputedMember(c,e,b,d);case r.CallExpression:return g=[],p(a.arguments,function(a){g.push(f.recurse(a))}),a.filter&&(e=this.$filter(a.callee.name)),a.filter||(e=this.recurse(a.callee,!0)),a.filter?function(a,c,d,f){for(var n=[],q=0;q":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)>b(c,e,f,g);return d?{value:c}:c}},"binary<=":function(a,b,d){return function(c,e,f,g){c=a(c,e,f, -g)<=b(c,e,f,g);return d?{value:c}:c}},"binary>=":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)>=b(c,e,f,g);return d?{value:c}:c}},"binary&&":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)&&b(c,e,f,g);return d?{value:c}:c}},"binary||":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)||b(c,e,f,g);return d?{value:c}:c}},"ternary?:":function(a,b,d,c){return function(e,f,g,k){e=a(e,f,g,k)?b(e,f,g,k):d(e,f,g,k);return c?{value:e}:e}},value:function(a,b){return function(){return b?{context:void 0, -name:void 0,value:a}:a}},identifier:function(a,b,d){return function(c,e,f,g){c=e&&a in e?e:c;d&&1!==d&&c&&null==c[a]&&(c[a]={});e=c?c[a]:void 0;return b?{context:c,name:a,value:e}:e}},computedMember:function(a,b,d,c){return function(e,f,g,k){var h=a(e,f,g,k),l,m;null!=h&&(l=b(e,f,g,k),l+="",c&&1!==c&&h&&!h[l]&&(h[l]={}),m=h[l]);return d?{context:h,name:l,value:m}:m}},nonComputedMember:function(a,b,d,c){return function(e,f,g,k){e=a(e,f,g,k);c&&1!==c&&e&&null==e[b]&&(e[b]={});f=null!=e?e[b]:void 0; -return d?{context:e,name:b,value:f}:f}},inputs:function(a,b){return function(d,c,e,f){return f?f[b]:a(d,c,e)}}};yc.prototype={constructor:yc,parse:function(a){a=this.ast.ast(a);var b=this.astCompiler.compile(a);b.literal=0===a.body.length||1===a.body.length&&(a.body[0].expression.type===r.Literal||a.body[0].expression.type===r.ArrayExpression||a.body[0].expression.type===r.ObjectExpression);b.constant=a.constant;return b}};var wa=M("$sce"),oa={HTML:"html",CSS:"css",URL:"url",RESOURCE_URL:"resourceUrl", -JS:"js"},Bc=/_([a-z])/g,Gg=M("$compile"),X=u.document.createElement("a"),Od=ua(u.location.href);Pd.$inject=["$document"];ed.$inject=["$provide"];var Wd=22,Vd=".",Dc="0";Qd.$inject=["$locale"];Sd.$inject=["$locale"];var Rg={yyyy:da("FullYear",4,0,!1,!0),yy:da("FullYear",2,0,!0,!0),y:da("FullYear",1,0,!1,!0),MMMM:nb("Month"),MMM:nb("Month",!0),MM:da("Month",2,1),M:da("Month",1,1),LLLL:nb("Month",!1,!0),dd:da("Date",2),d:da("Date",1),HH:da("Hours",2),H:da("Hours",1),hh:da("Hours",2,-12),h:da("Hours", -1,-12),mm:da("Minutes",2),m:da("Minutes",1),ss:da("Seconds",2),s:da("Seconds",1),sss:da("Milliseconds",3),EEEE:nb("Day"),EEE:nb("Day",!0),a:function(a,b){return 12>a.getHours()?b.AMPMS[0]:b.AMPMS[1]},Z:function(a,b,d){a=-1*d;return a=(0<=a?"+":"")+(Nb(Math[0=a.getFullYear()?b.ERANAMES[0]:b.ERANAMES[1]}},Qg=/((?:[^yMLdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|m+|s+|a|Z|G+|w+))([\s\S]*)/, -Pg=/^-?\d+$/;Rd.$inject=["$locale"];var Kg=ka(N),Lg=ka(vb);Td.$inject=["$parse"];var He=ka({restrict:"E",compile:function(a,b){if(!b.href&&!b.xlinkHref)return function(a,b){if("a"===b[0].nodeName.toLowerCase()){var e="[object SVGAnimatedString]"===ha.call(b.prop("href"))?"xlink:href":"href";b.on("click",function(a){b.attr(e)||a.preventDefault()})}}}}),wb={};p(Hb,function(a,b){function d(a,d,e){a.$watch(e[c],function(a){e.$set(b,!!a)})}if("multiple"!==a){var c=Ea("ng-"+b),e=d;"checked"===a&&(e=function(a, -b,e){e.ngModel!==e[c]&&d(a,b,e)});wb[c]=function(){return{restrict:"A",priority:100,link:e}}}});p(sd,function(a,b){wb[b]=function(){return{priority:100,link:function(a,c,e){if("ngPattern"===b&&"/"===e.ngPattern.charAt(0)&&(c=e.ngPattern.match(Vg))){e.$set("ngPattern",new RegExp(c[1],c[2]));return}a.$watch(e[b],function(a){e.$set(b,a)})}}}});p(["src","srcset","href"],function(a){var b=Ea("ng-"+a);wb[b]=function(){return{priority:99,link:function(d,c,e){var f=a,g=a;"href"===a&&"[object SVGAnimatedString]"=== -ha.call(c.prop("href"))&&(g="xlinkHref",e.$attr[g]="xlink:href",f=null);e.$observe(b,function(b){b?(e.$set(g,b),Ca&&f&&c.prop(f,e[g])):"href"===a&&e.$set(g,null)})}}}});var Pb={$addControl:C,$$renameControl:function(a,b){a.$name=b},$removeControl:C,$setValidity:C,$setDirty:C,$setPristine:C,$setSubmitted:C};Ob.$inject=["$element","$attrs","$scope","$animate","$interpolate"];Ob.prototype={$rollbackViewValue:function(){p(this.$$controls,function(a){a.$rollbackViewValue()})},$commitViewValue:function(){p(this.$$controls, -function(a){a.$commitViewValue()})},$addControl:function(a){Ia(a.$name,"input");this.$$controls.push(a);a.$name&&(this[a.$name]=a);a.$$parentForm=this},$$renameControl:function(a,b){var d=a.$name;this[d]===a&&delete this[d];this[b]=a;a.$name=b},$removeControl:function(a){a.$name&&this[a.$name]===a&&delete this[a.$name];p(this.$pending,function(b,d){this.$setValidity(d,null,a)},this);p(this.$error,function(b,d){this.$setValidity(d,null,a)},this);p(this.$$success,function(b,d){this.$setValidity(d,null, -a)},this);db(this.$$controls,a);a.$$parentForm=Pb},$setDirty:function(){this.$$animate.removeClass(this.$$element,Za);this.$$animate.addClass(this.$$element,Ub);this.$dirty=!0;this.$pristine=!1;this.$$parentForm.$setDirty()},$setPristine:function(){this.$$animate.setClass(this.$$element,Za,Ub+" ng-submitted");this.$dirty=!1;this.$pristine=!0;this.$submitted=!1;p(this.$$controls,function(a){a.$setPristine()})},$setUntouched:function(){p(this.$$controls,function(a){a.$setUntouched()})},$setSubmitted:function(){this.$$animate.addClass(this.$$element, -"ng-submitted");this.$submitted=!0;this.$$parentForm.$setSubmitted()}};ae({clazz:Ob,set:function(a,b,d){var c=a[b];c?-1===c.indexOf(d)&&c.push(d):a[b]=[d]},unset:function(a,b,d){var c=a[b];c&&(db(c,d),0===c.length&&delete a[b])}});var ie=function(a){return["$timeout","$parse",function(b,d){function c(a){return""===a?d('this[""]').assign:d(a).assign||C}return{name:"form",restrict:a?"EAC":"E",require:["form","^^?form"],controller:Ob,compile:function(d,f){d.addClass(Za).addClass(ob);var g=f.name?"name": -a&&f.ngForm?"ngForm":!1;return{pre:function(a,d,e,f){var n=f[0];if(!("action"in e)){var q=function(b){a.$apply(function(){n.$commitViewValue();n.$setSubmitted()});b.preventDefault()};d[0].addEventListener("submit",q);d.on("$destroy",function(){b(function(){d[0].removeEventListener("submit",q)},0,!1)})}(f[1]||n.$$parentForm).$addControl(n);var p=g?c(n.$name):C;g&&(p(a,n),e.$observe(g,function(b){n.$name!==b&&(p(a,void 0),n.$$parentForm.$$renameControl(n,b),p=c(n.$name),p(a,n))}));d.on("$destroy",function(){n.$$parentForm.$removeControl(n); -p(a,void 0);Q(n,Pb)})}}}}}]},Ie=ie(),Ue=ie(!0),Sg=/^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-][0-2]\d:[0-5]\d|Z)$/,dh=/^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i,eh=/^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/,Tg=/^\s*(-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/,je=/^(\d{4,})-(\d{2})-(\d{2})$/, -ke=/^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,Lc=/^(\d{4,})-W(\d\d)$/,le=/^(\d{4,})-(\d\d)$/,me=/^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,ce=T();p(["date","datetime-local","month","time","week"],function(a){ce[a]=!0});var ne={text:function(a,b,d,c,e,f){Wa(a,b,d,c,e,f);Gc(c)},date:pb("date",je,Qb(je,["yyyy","MM","dd"]),"yyyy-MM-dd"),"datetime-local":pb("datetimelocal",ke,Qb(ke,"yyyy MM dd HH mm ss sss".split(" ")),"yyyy-MM-ddTHH:mm:ss.sss"),time:pb("time",me,Qb(me,["HH","mm", -"ss","sss"]),"HH:mm:ss.sss"),week:pb("week",Lc,function(a,b){if(ea(a))return a;if(D(a)){Lc.lastIndex=0;var d=Lc.exec(a);if(d){var c=+d[1],e=+d[2],f=d=0,g=0,k=0,h=Xd(c),e=7*(e-1);b&&(d=b.getHours(),f=b.getMinutes(),g=b.getSeconds(),k=b.getMilliseconds());return new Date(c,0,h.getDate()+e,d,f,g,k)}}return NaN},"yyyy-Www"),month:pb("month",le,Qb(le,["yyyy","MM"]),"yyyy-MM"),number:function(a,b,d,c,e,f){Hc(a,b,d,c);de(c);Wa(a,b,d,c,e,f);var g,k;if(t(d.min)||d.ngMin)c.$validators.min=function(a){return c.$isEmpty(a)|| -w(g)||a>=g},d.$observe("min",function(a){g=Xa(a);c.$validate()});if(t(d.max)||d.ngMax)c.$validators.max=function(a){return c.$isEmpty(a)||w(k)||a<=k},d.$observe("max",function(a){k=Xa(a);c.$validate()});if(t(d.step)||d.ngStep){var h;c.$validators.step=function(a,b){return c.$isEmpty(b)||w(h)||ee(b,g||0,h)};d.$observe("step",function(a){h=Xa(a);c.$validate()})}},url:function(a,b,d,c,e,f){Wa(a,b,d,c,e,f);Gc(c);c.$$parserName="url";c.$validators.url=function(a,b){var d=a||b;return c.$isEmpty(d)||dh.test(d)}}, -email:function(a,b,d,c,e,f){Wa(a,b,d,c,e,f);Gc(c);c.$$parserName="email";c.$validators.email=function(a,b){var d=a||b;return c.$isEmpty(d)||eh.test(d)}},radio:function(a,b,d,c){var e=!d.ngTrim||"false"!==R(d.ngTrim);w(d.name)&&b.attr("name",++rb);b.on("click",function(a){var g;b[0].checked&&(g=d.value,e&&(g=R(g)),c.$setViewValue(g,a&&a.type))});c.$render=function(){var a=d.value;e&&(a=R(a));b[0].checked=a===c.$viewValue};d.$observe("value",c.$render)},range:function(a,b,d,c,e,f){function g(a,c){b.attr(a, -d[a]);d.$observe(a,c)}function k(a){n=Xa(a);U(c.$modelValue)||(m?(a=b.val(),n>a&&(a=n,b.val(a)),c.$setViewValue(a)):c.$validate())}function h(a){q=Xa(a);U(c.$modelValue)||(m?(a=b.val(),q=n},g("min",k));e&&(c.$validators.max=m?function(){return!0}:function(a,b){return c.$isEmpty(b)||w(q)||b<=q},g("max",h));f&&(c.$validators.step=m?function(){return!r.stepMismatch}:function(a,b){return c.$isEmpty(b)||w(p)||ee(b,n||0,p)},g("step",l))},checkbox:function(a,b,d,c,e, -f,g,k){var h=fe(k,a,"ngTrueValue",d.ngTrueValue,!0),l=fe(k,a,"ngFalseValue",d.ngFalseValue,!1);b.on("click",function(a){c.$setViewValue(b[0].checked,a&&a.type)});c.$render=function(){b[0].checked=c.$viewValue};c.$isEmpty=function(a){return!1===a};c.$formatters.push(function(a){return sa(a,h)});c.$parsers.push(function(a){return a?h:l})},hidden:C,button:C,submit:C,reset:C,file:C},Zc=["$browser","$sniffer","$filter","$parse",function(a,b,d,c){return{restrict:"E",require:["?ngModel"],link:{pre:function(e, -f,g,k){k[0]&&(ne[N(g.type)]||ne.text)(e,f,g,k[0],b,a,d,c)}}}}],fh=/^(true|false|\d+)$/,mf=function(){function a(a,d,c){var e=t(c)?c:9===Ca?"":null;a.prop("value",e);d.$set("value",c)}return{restrict:"A",priority:100,compile:function(b,d){return fh.test(d.ngValue)?function(b,d,f){b=b.$eval(f.ngValue);a(d,f,b)}:function(b,d,f){b.$watch(f.ngValue,function(b){a(d,f,b)})}}}},Me=["$compile",function(a){return{restrict:"AC",compile:function(b){a.$$addBindingClass(b);return function(b,c,e){a.$$addBindingInfo(c, -e.ngBind);c=c[0];b.$watch(e.ngBind,function(a){c.textContent=fc(a)})}}}}],Oe=["$interpolate","$compile",function(a,b){return{compile:function(d){b.$$addBindingClass(d);return function(c,d,f){c=a(d.attr(f.$attr.ngBindTemplate));b.$$addBindingInfo(d,c.expressions);d=d[0];f.$observe("ngBindTemplate",function(a){d.textContent=w(a)?"":a})}}}}],Ne=["$sce","$parse","$compile",function(a,b,d){return{restrict:"A",compile:function(c,e){var f=b(e.ngBindHtml),g=b(e.ngBindHtml,function(b){return a.valueOf(b)}); -d.$$addBindingClass(c);return function(b,c,e){d.$$addBindingInfo(c,e.ngBindHtml);b.$watch(g,function(){var d=f(b);c.html(a.getTrustedHtml(d)||"")})}}}}],lf=ka({restrict:"A",require:"ngModel",link:function(a,b,d,c){c.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),Pe=Jc("",!0),Re=Jc("Odd",0),Qe=Jc("Even",1),Se=Qa({compile:function(a,b){b.$set("ngCloak",void 0);a.removeClass("ng-cloak")}}),Te=[function(){return{restrict:"A",scope:!0,controller:"@",priority:500}}],dd={},gh={blur:!0,focus:!0}; -p("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "),function(a){var b=Ea("ng-"+a);dd[b]=["$parse","$rootScope",function(d,c){return{restrict:"A",compile:function(e,f){var g=d(f[b]);return function(b,d){d.on(a,function(d){var e=function(){g(b,{$event:d})};gh[a]&&c.$$phase?b.$evalAsync(e):b.$apply(e)})}}}}]});var We=["$animate","$compile",function(a,b){return{multiElement:!0,transclude:"element",priority:600, -terminal:!0,restrict:"A",$$tlb:!0,link:function(d,c,e,f,g){var k,h,l;d.$watch(e.ngIf,function(d){d?h||g(function(d,f){h=f;d[d.length++]=b.$$createComment("end ngIf",e.ngIf);k={clone:d};a.enter(d,c.parent(),c)}):(l&&(l.remove(),l=null),h&&(h.$destroy(),h=null),k&&(l=ub(k.clone),a.leave(l).done(function(a){!1!==a&&(l=null)}),k=null))})}}}],Xe=["$templateRequest","$anchorScroll","$animate",function(a,b,d){return{restrict:"ECA",priority:400,terminal:!0,transclude:"element",controller:$.noop,compile:function(c, -e){var f=e.ngInclude||e.src,g=e.onload||"",k=e.autoscroll;return function(c,e,m,n,q){var p=0,r,z,v,s=function(){z&&(z.remove(),z=null);r&&(r.$destroy(),r=null);v&&(d.leave(v).done(function(a){!1!==a&&(z=null)}),z=v,v=null)};c.$watch(f,function(f){var m=function(a){!1===a||!t(k)||k&&!c.$eval(k)||b()},y=++p;f?(a(f,!0).then(function(a){if(!c.$$destroyed&&y===p){var b=c.$new();n.template=a;a=q(b,function(a){s();d.enter(a,null,e).done(m)});r=b;v=a;r.$emit("$includeContentLoaded",f);c.$eval(g)}},function(){c.$$destroyed|| -y!==p||(s(),c.$emit("$includeContentError",f))}),c.$emit("$includeContentRequested",f)):(s(),n.template=null)})}}}}],of=["$compile",function(a){return{restrict:"ECA",priority:-400,require:"ngInclude",link:function(b,d,c,e){ha.call(d[0]).match(/SVG/)?(d.empty(),a(fd(e.template,u.document).childNodes)(b,function(a){d.append(a)},{futureParentElement:d})):(d.html(e.template),a(d.contents())(b))}}}],Ye=Qa({priority:450,compile:function(){return{pre:function(a,b,d){a.$eval(d.ngInit)}}}}),kf=function(){return{restrict:"A", -priority:100,require:"ngModel",link:function(a,b,d,c){var e=d.ngList||", ",f="false"!==d.ngTrim,g=f?R(e):e;c.$parsers.push(function(a){if(!w(a)){var b=[];a&&p(a.split(g),function(a){a&&b.push(f?R(a):a)});return b}});c.$formatters.push(function(a){if(I(a))return a.join(e)});c.$isEmpty=function(a){return!a||!a.length}}}},ob="ng-valid",$d="ng-invalid",Za="ng-pristine",Ub="ng-dirty",qb=M("ngModel");Rb.$inject="$scope $exceptionHandler $attrs $element $parse $animate $timeout $q $interpolate".split(" "); -Rb.prototype={$$initGetterSetters:function(){if(this.$options.getOption("getterSetter")){var a=this.$$parse(this.$$attr.ngModel+"()"),b=this.$$parse(this.$$attr.ngModel+"($$$p)");this.$$ngModelGet=function(b){var c=this.$$parsedNgModel(b);B(c)&&(c=a(b));return c};this.$$ngModelSet=function(a,c){B(this.$$parsedNgModel(a))?b(a,{$$$p:c}):this.$$parsedNgModelAssign(a,c)}}else if(!this.$$parsedNgModel.assign)throw qb("nonassign",this.$$attr.ngModel,Aa(this.$$element));},$render:C,$isEmpty:function(a){return w(a)|| -""===a||null===a||a!==a},$$updateEmptyClasses:function(a){this.$isEmpty(a)?(this.$$animate.removeClass(this.$$element,"ng-not-empty"),this.$$animate.addClass(this.$$element,"ng-empty")):(this.$$animate.removeClass(this.$$element,"ng-empty"),this.$$animate.addClass(this.$$element,"ng-not-empty"))},$setPristine:function(){this.$dirty=!1;this.$pristine=!0;this.$$animate.removeClass(this.$$element,Ub);this.$$animate.addClass(this.$$element,Za)},$setDirty:function(){this.$dirty=!0;this.$pristine=!1;this.$$animate.removeClass(this.$$element, -Za);this.$$animate.addClass(this.$$element,Ub);this.$$parentForm.$setDirty()},$setUntouched:function(){this.$touched=!1;this.$untouched=!0;this.$$animate.setClass(this.$$element,"ng-untouched","ng-touched")},$setTouched:function(){this.$touched=!0;this.$untouched=!1;this.$$animate.setClass(this.$$element,"ng-touched","ng-untouched")},$rollbackViewValue:function(){this.$$timeout.cancel(this.$$pendingDebounce);this.$viewValue=this.$$lastCommittedViewValue;this.$render()},$validate:function(){if(!U(this.$modelValue)){var a= -this.$$lastCommittedViewValue,b=this.$$rawModelValue,d=this.$valid,c=this.$modelValue,e=this.$options.getOption("allowInvalid"),f=this;this.$$runValidators(b,a,function(a){e||d===a||(f.$modelValue=a?b:void 0,f.$modelValue!==c&&f.$$writeModelToScope())})}},$$runValidators:function(a,b,d){function c(){var c=!0;p(h.$validators,function(d,e){var g=Boolean(d(a,b));c=c&&g;f(e,g)});return c?!0:(p(h.$asyncValidators,function(a,b){f(b,null)}),!1)}function e(){var c=[],d=!0;p(h.$asyncValidators,function(e, -g){var h=e(a,b);if(!h||!B(h.then))throw qb("nopromise",h);f(g,void 0);c.push(h.then(function(){f(g,!0)},function(){d=!1;f(g,!1)}))});c.length?h.$$q.all(c).then(function(){g(d)},C):g(!0)}function f(a,b){k===h.$$currentValidationRunId&&h.$setValidity(a,b)}function g(a){k===h.$$currentValidationRunId&&d(a)}this.$$currentValidationRunId++;var k=this.$$currentValidationRunId,h=this;(function(){var a=h.$$parserName||"parse";if(w(h.$$parserValid))f(a,null);else return h.$$parserValid||(p(h.$validators,function(a, -b){f(b,null)}),p(h.$asyncValidators,function(a,b){f(b,null)})),f(a,h.$$parserValid),h.$$parserValid;return!0})()?c()?e():g(!1):g(!1)},$commitViewValue:function(){var a=this.$viewValue;this.$$timeout.cancel(this.$$pendingDebounce);if(this.$$lastCommittedViewValue!==a||""===a&&this.$$hasNativeValidators)this.$$updateEmptyClasses(a),this.$$lastCommittedViewValue=a,this.$pristine&&this.$setDirty(),this.$$parseAndValidate()},$$parseAndValidate:function(){var a=this.$$lastCommittedViewValue,b=this;if(this.$$parserValid= -w(a)?void 0:!0)for(var d=0;de||c.$isEmpty(b)||b.length<=e}}}}},bd=function(){return{restrict:"A",require:"?ngModel",link:function(a,b,d,c){if(c){var e=0;d.$observe("minlength",function(a){e=Z(a)||0;c.$validate()});c.$validators.minlength=function(a,b){return c.$isEmpty(b)||b.length>=e}}}}};u.angular.bootstrap?u.console&&console.log("WARNING: Tried to load angular more than once."): -(Be(),Ee($),$.module("ngLocale",[],["$provide",function(a){function b(a){a+="";var b=a.indexOf(".");return-1==b?0:a.length-b-1}a.value("$locale",{DATETIME_FORMATS:{AMPMS:["AM","PM"],DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),ERANAMES:["Before Christ","Anno Domini"],ERAS:["BC","AD"],FIRSTDAYOFWEEK:6,MONTH:"January February March April May June July August September October November December".split(" "),SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "),SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "), -STANDALONEMONTH:"January February March April May June July August September October November December".split(" "),WEEKENDRANGE:[5,6],fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",medium:"MMM d, y h:mm:ss a",mediumDate:"MMM d, y",mediumTime:"h:mm:ss a","short":"M/d/yy h:mm a",shortDate:"M/d/yy",shortTime:"h:mm a"},NUMBER_FORMATS:{CURRENCY_SYM:"$",DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{gSize:3,lgSize:3,maxFrac:3,minFrac:0,minInt:1,negPre:"-",negSuf:"",posPre:"",posSuf:""},{gSize:3,lgSize:3,maxFrac:2, -minFrac:2,minInt:1,negPre:"-\u00a4",negSuf:"",posPre:"\u00a4",posSuf:""}]},id:"en-us",localeID:"en_US",pluralCat:function(a,c){var e=a|0,f=c;void 0===f&&(f=Math.min(b(a),3));Math.pow(10,f);return 1==e&&0==f?"one":"other"}})}]),A(function(){we(u.document,Uc)}))})(window);!window.angular.$$csp().noInlineStyle&&window.angular.element(document.head).prepend(''); -//# sourceMappingURL=angular.min.js.map +(function(B){'use strict';function oe(a){if(F(a))v(a.objectMaxDepth)&&(Vb.objectMaxDepth=Wb(a.objectMaxDepth)?a.objectMaxDepth:NaN),v(a.urlErrorParamsEnabled)&&Fa(a.urlErrorParamsEnabled)&&(Vb.urlErrorParamsEnabled=a.urlErrorParamsEnabled);else return Vb}function Wb(a){return ba(a)&&0c)return"...";var d=b.$$hashKey,f;if(I(a)){f=0;for(var g=a.length;f
").append(a).html();try{return a[0].nodeType===Oa?O(b):b.match(/^(<[^>]+>)/)[1].replace(/^<([\w-]+)/,function(a,b){return"<"+O(b)})}catch(d){return O(b)}}function Sc(a){try{return decodeURIComponent(a)}catch(b){}}function fc(a){var b={};r((a||"").split("&"), +function(a){var c,e,f;a&&(e=a=a.replace(/\+/g,"%20"),c=a.indexOf("="),-1!==c&&(e=a.substring(0,c),f=a.substring(c+1)),e=Sc(e),v(e)&&(f=v(f)?Sc(f):!0,sa.call(b,e)?I(b[e])?b[e].push(f):b[e]=[b[e],f]:b[e]=f))});return b}function ve(a){var b=[];r(a,function(a,c){I(a)?r(a,function(a){b.push(ca(c,!0)+(!0===a?"":"="+ca(a,!0)))}):b.push(ca(c,!0)+(!0===a?"":"="+ca(a,!0)))});return b.length?b.join("&"):""}function gc(a){return ca(a,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function ca(a, +b){return encodeURIComponent(a).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%3B/gi,";").replace(/%20/g,b?"%20":"+")}function we(a,b){var d,c,e=Pa.length;for(c=0;c protocol indicates an extension, document.location.href does not match.")}catch(f){}}function Tc(a,b,d){F(d)||(d={});d=R({strictDi:!1},d);var c=function(){a=y(a);if(a.injector()){var c=a[0]===B.document?"document":ya(a);throw Ia("btstrpd",c.replace(//,">"));}b=b||[];b.unshift(["$provide",function(b){b.value("$rootElement",a)}]);d.debugInfoEnabled&& +b.push(["$compileProvider",function(a){a.debugInfoEnabled(!0)}]);b.unshift("ng");c=fb(b,d.strictDi);c.invoke(["$rootScope","$rootElement","$compile","$injector",function(a,b,c,d){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return c},e=/^NG_ENABLE_DEBUG_INFO!/,f=/^NG_DEFER_BOOTSTRAP!/;B&&e.test(B.name)&&(d.debugInfoEnabled=!0,B.name=B.name.replace(e,""));if(B&&!f.test(B.name))return c();B.name=B.name.replace(f,"");ea.resumeBootstrap=function(a){r(a,function(a){b.push(a)});return c()};z(ea.resumeDeferredBootstrap)&& +ea.resumeDeferredBootstrap()}function ze(){B.name="NG_ENABLE_DEBUG_INFO!"+B.name;B.location.reload()}function Ae(a){a=ea.element(a).injector();if(!a)throw Ia("test");return a.get("$$testability")}function Uc(a,b){b=b||"_";return a.replace(Be,function(a,c){return(c?b:"")+a.toLowerCase()})}function Ce(){var a;if(!Vc){var b=qb();(rb=x(b)?B.jQuery:b?B[b]:void 0)&&rb.fn.on?(y=rb,R(rb.fn,{scope:Wa.scope,isolateScope:Wa.isolateScope,controller:Wa.controller,injector:Wa.injector,inheritedData:Wa.inheritedData})): +y=W;a=y.cleanData;y.cleanData=function(b){for(var c,e=0,f;null!=(f=b[e]);e++)(c=(y._data(f)||{}).events)&&c.$destroy&&y(f).triggerHandler("$destroy");a(b)};ea.element=y;Vc=!0}}function gb(a,b,d){if(!a)throw Ia("areq",b||"?",d||"required");return a}function sb(a,b,d){d&&I(a)&&(a=a[a.length-1]);gb(z(a),b,"not a function, got "+(a&&"object"===typeof a?a.constructor.name||"Object":typeof a));return a}function Qa(a,b){if("hasOwnProperty"===a)throw Ia("badname",b);}function De(a,b,d){if(!b)return a;b=b.split("."); +for(var c,e=a,f=b.length,g=0;g")+c[2];for(c=c[0];c--;)d=d.lastChild;f=db(f,d.childNodes);d=e.firstChild;d.textContent=""}else f.push(b.createTextNode(a));e.textContent="";e.innerHTML="";r(f,function(a){e.appendChild(a)});return e}function W(a){if(a instanceof W)return a;var b;C(a)&&(a=T(a),b=!0);if(!(this instanceof W)){if(b&&"<"!==a.charAt(0))throw mc("nosel");return new W(a)}if(b){b= +B.document;var d;a=(d=kg.exec(a))?[b.createElement(d[1])]:(d=dd(a,b))?d.childNodes:[];nc(this,a)}else z(a)?ed(a):nc(this,a)}function oc(a){return a.cloneNode(!0)}function yb(a,b){!b&&kc(a)&&y.cleanData([a]);a.querySelectorAll&&y.cleanData(a.querySelectorAll("*"))}function fd(a){for(var b in a)return!1;return!0}function gd(a){var b=a.ng339,d=b&&Ja[b],c=d&&d.events,d=d&&d.data;d&&!fd(d)||c&&!fd(c)||(delete Ja[b],a.ng339=void 0)}function hd(a,b,d,c){if(v(c))throw mc("offargs");var e=(c=zb(a))&&c.events, +f=c&&c.handle;if(f){if(b){var g=function(b){var c=e[b];v(d)&&cb(c||[],d);v(d)&&c&&0l&&this.remove(n.key);return b}},get:function(a){if(l";b=Ea.firstChild.attributes;var d=b[0];b.removeNamedItem(d.name);d.value=c;a.attributes.setNamedItem(d)}function ra(a,b){try{a.addClass(b)}catch(c){}} +function fa(a,b,c,d,e){a instanceof y||(a=y(a));var f=Xa(a,b,a,c,d,e);fa.$$addScopeClass(a);var g=null;return function(b,c,d){if(!a)throw aa("multilink");gb(b,"scope");e&&e.needsNewScope&&(b=b.$parent.$new());d=d||{};var h=d.parentBoundTranscludeFn,k=d.transcludeControllers;d=d.futureParentElement;h&&h.$$boundTransclude&&(h=h.$$boundTransclude);g||(g=(d=d&&d[0])?"foreignobject"!==ta(d)&&ma.call(d).match(/SVG/)?"svg":"html":"html");d="html"!==g?y(ja(g,y("
").append(a).html())):c?Wa.clone.call(a): +a;if(k)for(var l in k)d.data("$"+l+"Controller",k[l].instance);fa.$$addScopeInfo(d,b);c&&c(d,b);f&&f(b,d,d,h);c||(a=f=null);return d}}function Xa(a,b,c,d,e,f){function g(a,c,d,e){var f,k,l,m,q,n,G;if(J)for(G=Array(c.length),m=0;mt.priority)break;if(N=t.scope)t.templateUrl||(F(N)?(ca("new/isolated scope",s||G,t,H),s=t):ca("new/isolated scope",s,t,H)),G=G||t;K=t.name;if(!na&&(t.replace&&(t.templateUrl||t.template)||t.transclude&&!t.$$tlb)){for(N=ra+1;na=a[N++];)if(na.transclude&&!na.$$tlb||na.replace&&(na.templateUrl||na.template)){Ib=!0;break}na=!0}!t.templateUrl&&t.controller&&(u=u||S(),ca("'"+K+"' controller", +u[K],t,H),u[K]=t);if(N=t.transclude)if(E=!0,t.$$tlb||(ca("transclusion",L,t,H),L=t),"element"===N)P=!0,n=t.priority,X=H,H=d.$$element=y(fa.$$createComment(K,d[K])),b=H[0],pa(f,Ga.call(X,0),b),Q=Y(Ib,X,e,n,g&&g.name,{nonTlbTranscludeDirective:L});else{var ka=S();if(F(N)){X=B.document.createDocumentFragment();var Xa=S(),M=S();r(N,function(a,b){var c="?"===a.charAt(0);a=c?a.substring(1):a;Xa[a]=b;ka[b]=null;M[b]=c});r(H.contents(),function(a){var b=Xa[va(ta(a))];b?(M[b]=!0,ka[b]=ka[b]||B.document.createDocumentFragment(), +ka[b].appendChild(a)):X.appendChild(a)});r(M,function(a,b){if(!a)throw aa("reqslot",b);});for(var O in ka)ka[O]&&(Q=y(ka[O].childNodes),ka[O]=Y(Ib,Q,e));X=y(X.childNodes)}else X=y(oc(b)).contents();H.empty();Q=Y(Ib,X,e,void 0,void 0,{needsNewScope:t.$$isolateScope||t.$$newScope});Q.$$slots=ka}if(t.template)if(D=!0,ca("template",w,t,H),w=t,N=z(t.template)?t.template(H,d):t.template,N=Na(N),t.replace){g=t;X=lc.test(N)?qd(ja(t.templateNamespace,T(N))):[];b=X[0];if(1!==X.length||1!==b.nodeType)throw aa("tplrt", +K,"");pa(f,H,b);C={$attr:{}};N=rc(b,[],C);var zg=a.splice(ra+1,a.length-(ra+1));(s||G)&&da(N,s,G);a=a.concat(N).concat(zg);ha(d,C);C=a.length}else H.html(N);if(t.templateUrl)D=!0,ca("template",w,t,H),w=t,t.replace&&(g=t),q=ia(a.splice(ra,a.length-ra),H,d,f,E&&Q,h,k,{controllerDirectives:u,newScopeDirective:G!==t&&G,newIsolateScopeDirective:s,templateDirective:w,nonTlbTranscludeDirective:L}),C=a.length;else if(t.compile)try{p=t.compile(H,d,Q);var V=t.$$originalDirective||t;z(p)?m(null,Va(V,p),A,ib): +p&&m(Va(V,p.pre),Va(V,p.post),A,ib)}catch(ea){c(ea,ya(H))}t.terminal&&(q.terminal=!0,n=Math.max(n,t.priority))}q.scope=G&&!0===G.scope;q.transcludeOnThisElement=E;q.templateOnThisElement=D;q.transclude=Q;l.hasElementTranscludeDirective=P;return q}function $(a,b,c,d){var e;if(C(b)){var f=b.match(l);b=b.substring(f[0].length);var g=f[1]||f[3],f="?"===f[2];"^^"===g?c=c.parent():e=(e=d&&d[b])&&e.instance;if(!e){var h="$"+b+"Controller";e="^^"===g&&c[0]&&9===c[0].nodeType?null:g?c.inheritedData(h):c.data(h)}if(!e&& +!f)throw aa("ctreq",b,a);}else if(I(b))for(e=[],g=0,f=b.length;gc.priority)&&-1!==c.restrict.indexOf(e)){k&&(c=$b(c,{$$start:k,$$end:l}));if(!c.$$bindings){var J=m=c,G=c.name,u={isolateScope:null,bindToController:null};F(J.scope)&&(!0===J.bindToController?(u.bindToController=d(J.scope,G,!0),u.isolateScope={}):u.isolateScope=d(J.scope,G,!1));F(J.bindToController)&&(u.bindToController=d(J.bindToController, +G,!0));if(u.bindToController&&!J.controller)throw aa("noctrl",G);m=m.$$bindings=u;F(m.isolateScope)&&(c.$$isolateBindings=m.isolateScope)}b.push(c);m=c}}return m}function ea(b){if(f.hasOwnProperty(b))for(var c=a.get(b+"Directive"),d=0,e=c.length;d"+b+"";return c.childNodes[0].childNodes;default:return b}}function wa(a,b){if("srcdoc"===b)return P.HTML;if("src"===b||"ngSrc"===b)return-1===["img","video","audio","source","track"].indexOf(a)?P.RESOURCE_URL:P.MEDIA_URL;if("xlinkHref"===b)return"image"===a?P.MEDIA_URL: +"a"===a?P.URL:P.RESOURCE_URL;if("form"===a&&"action"===b||"base"===a&&"href"===b||"link"===a&&"href"===b)return P.RESOURCE_URL;if("a"===a&&("href"===b||"ngHref"===b))return P.URL}function xa(a,b){var c=b.toLowerCase();return w[a+"|"+c]||w["*|"+c]}function Da(a){return na(P.valueOf(a),"ng-prop-srcset")}function Ha(a,b,c,d){if(m.test(d))throw aa("nodomevents");a=ta(a);var e=xa(a,d),f=Ta;"srcset"!==d||"img"!==a&&"source"!==a?e&&(f=P.getTrusted.bind(P,e)):f=Da;b.push({priority:100,compile:function(a, +b){var e=q(b[c]),g=q(b[c],function(a){return P.valueOf(a)});return{pre:function(a,b){function c(){var g=e(a);b.prop(d,f(g))}c();a.$watch(g,c)}}}})}function Ia(a,c,d,e,f){var g=ta(a),k=wa(g,e),l=h[e]||f,n=b(d,!f,k,l);if(n){if("multiple"===e&&"select"===g)throw aa("selmulti",ya(a));if(m.test(e))throw aa("nodomevents");c.push({priority:100,compile:function(){return{pre:function(a,c,f){c=f.$$observers||(f.$$observers=S());var g=f[e];g!==d&&(n=g&&b(g,!0,k,l),d=g);n&&(f[e]=n(a),(c[e]||(c[e]=[])).$$inter= +!0,(f.$$observers&&f.$$observers[e].$$scope||a).$watch(n,function(a,b){"class"===e&&a!==b?f.$updateClass(a,b):f.$set(e,a)}))}}}})}}function pa(a,b,c){var d=b[0],e=b.length,f=d.parentNode,g,h;if(a)for(g=0,h=a.length;g=b)return a;for(;b--;){var d=a[b];(8===d.nodeType||d.nodeType===Oa&&""===d.nodeValue.trim())&&Bg.call(a,b,1)}return a}function xg(a,b){if(b&&C(b))return b;if(C(a)){var d=td.exec(a);if(d)return d[3]}}function Bf(){var a={};this.has=function(b){return a.hasOwnProperty(b)};this.register=function(b,d){Qa(b,"controller");F(b)?R(a, +b):a[b]=d};this.$get=["$injector",function(b){function d(a,b,d,g){if(!a||!F(a.$scope))throw M("$controller")("noscp",g,b);a.$scope[b]=d}return function(c,e,f,g){var k,h,l;f=!0===f;g&&C(g)&&(l=g);if(C(c)){g=c.match(td);if(!g)throw ud("ctrlfmt",c);h=g[1];l=l||g[3];c=a.hasOwnProperty(h)?a[h]:De(e.$scope,h,!0);if(!c)throw ud("ctrlreg",h);sb(c,h,!0)}if(f)return f=(I(c)?c[c.length-1]:c).prototype,k=Object.create(f||null),l&&d(e,l,k,h||c.name),R(function(){var a=b.invoke(c,k,e,h);a!==k&&(F(a)||z(a))&&(k= +a,l&&d(e,l,k,h||c.name));return k},{instance:k,identifier:l});k=b.instantiate(c,e,h);l&&d(e,l,k,h||c.name);return k}}]}function Cf(){this.$get=["$window",function(a){return y(a.document)}]}function Df(){this.$get=["$document","$rootScope",function(a,b){function d(){e=c.hidden}var c=a[0],e=c&&c.hidden;a.on("visibilitychange",d);b.$on("$destroy",function(){a.off("visibilitychange",d)});return function(){return e}}]}function Ef(){this.$get=["$log",function(a){return function(b,d){a.error.apply(a,arguments)}}]} +function tc(a){return F(a)?ha(a)?a.toISOString():eb(a):a}function Kf(){this.$get=function(){return function(a){if(!a)return"";var b=[];Nc(a,function(a,c){null===a||x(a)||z(a)||(I(a)?r(a,function(a){b.push(ca(c)+"="+ca(tc(a)))}):b.push(ca(c)+"="+ca(tc(a))))});return b.join("&")}}}function Lf(){this.$get=function(){return function(a){function b(a,e,f){I(a)?r(a,function(a,c){b(a,e+"["+(F(a)?c:"")+"]")}):F(a)&&!ha(a)?Nc(a,function(a,c){b(a,e+(f?"":"[")+c+(f?"":"]"))}):(z(a)&&(a=a()),d.push(ca(e)+"="+ +(null==a?"":ca(tc(a)))))}if(!a)return"";var d=[];b(a,"",!0);return d.join("&")}}}function uc(a,b){if(C(a)){var d=a.replace(Cg,"").trim();if(d){var c=b("Content-Type"),c=c&&0===c.indexOf(vd),e;(e=c)||(e=(e=d.match(Dg))&&Eg[e[0]].test(d));if(e)try{a=Qc(d)}catch(f){if(!c)return a;throw Kb("baddata",a,f);}}}return a}function wd(a){var b=S(),d;C(a)?r(a.split("\n"),function(a){d=a.indexOf(":");var e=O(T(a.substr(0,d)));a=T(a.substr(d+1));e&&(b[e]=b[e]?b[e]+", "+a:a)}):F(a)&&r(a,function(a,d){var f=O(d), +g=T(a);f&&(b[f]=b[f]?b[f]+", "+g:g)});return b}function xd(a){var b;return function(d){b||(b=wd(a));return d?(d=b[O(d)],void 0===d&&(d=null),d):b}}function yd(a,b,d,c){if(z(c))return c(a,b,d);r(c,function(c){a=c(a,b,d)});return a}function Jf(){var a=this.defaults={transformResponse:[uc],transformRequest:[function(a){return F(a)&&"[object File]"!==ma.call(a)&&"[object Blob]"!==ma.call(a)&&"[object FormData]"!==ma.call(a)?eb(a):a}],headers:{common:{Accept:"application/json, text/plain, */*"},post:oa(vc), +put:oa(vc),patch:oa(vc)},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",paramSerializer:"$httpParamSerializer",jsonpCallbackParam:"callback"},b=!1;this.useApplyAsync=function(a){return v(a)?(b=!!a,this):b};var d=this.interceptors=[],c=this.xsrfWhitelistedOrigins=[];this.$get=["$browser","$httpBackend","$$cookieReader","$cacheFactory","$rootScope","$q","$injector","$sce",function(e,f,g,k,h,l,m,q){function n(b){function c(a,b){for(var d=0,e=b.length;da?b:l.reject(b)}if(!F(b))throw M("$http")("badreq",b);if(!C(q.valueOf(b.url)))throw M("$http")("badreq",b.url);var g=R({method:"get",transformRequest:a.transformRequest,transformResponse:a.transformResponse,paramSerializer:a.paramSerializer,jsonpCallbackParam:a.jsonpCallbackParam}, +b);g.headers=function(b){var c=a.headers,e=R({},b.headers),f,g,h,c=R({},c.common,c[O(b.method)]);a:for(f in c){g=O(f);for(h in e)if(O(h)===g)continue a;e[f]=c[f]}return d(e,oa(b))}(b);g.method=ub(g.method);g.paramSerializer=C(g.paramSerializer)?m.get(g.paramSerializer):g.paramSerializer;e.$$incOutstandingRequestCount("$http");var h=[],k=[];b=l.resolve(g);r(w,function(a){(a.request||a.requestError)&&h.unshift(a.request,a.requestError);(a.response||a.responseError)&&k.push(a.response,a.responseError)}); +b=c(b,h);b=b.then(function(b){var c=b.headers,d=yd(b.data,xd(c),void 0,b.transformRequest);x(d)&&r(c,function(a,b){"content-type"===O(b)&&delete c[b]});x(b.withCredentials)&&!x(a.withCredentials)&&(b.withCredentials=a.withCredentials);return s(b,d).then(f,f)});b=c(b,k);return b=b.finally(function(){e.$$completeOutstandingRequest(A,"$http")})}function s(c,d){function e(a){if(a){var c={};r(a,function(a,d){c[d]=function(c){function d(){a(c)}b?h.$applyAsync(d):h.$$phase?d():h.$apply(d)}});return c}}function k(a, +c,d,e,f){function g(){m(c,a,d,e,f)}Q&&(200<=a&&300>a?Q.put(N,[a,c,wd(d),e,f]):Q.remove(N));b?h.$applyAsync(g):(g(),h.$$phase||h.$apply())}function m(a,b,d,e,f){b=-1<=b?b:0;(200<=b&&300>b?L.resolve:L.reject)({data:a,status:b,headers:xd(d),config:c,statusText:e,xhrStatus:f})}function s(a){m(a.data,a.status,oa(a.headers()),a.statusText,a.xhrStatus)}function w(){var a=n.pendingRequests.indexOf(c);-1!==a&&n.pendingRequests.splice(a,1)}var L=l.defer(),P=L.promise,Q,p,na=c.headers,y="jsonp"===O(c.method), +N=c.url;y?N=q.getTrustedResourceUrl(N):C(N)||(N=q.valueOf(N));N=t(N,c.paramSerializer(c.params));y&&(N=u(N,c.jsonpCallbackParam));n.pendingRequests.push(c);P.then(w,w);!c.cache&&!a.cache||!1===c.cache||"GET"!==c.method&&"JSONP"!==c.method||(Q=F(c.cache)?c.cache:F(a.cache)?a.cache:D);Q&&(p=Q.get(N),v(p)?p&&z(p.then)?p.then(s,s):I(p)?m(p[1],p[0],oa(p[2]),p[3],p[4]):m(p,200,{},"OK","complete"):Q.put(N,P));x(p)&&((p=ic(c.url)?g()[c.xsrfCookieName||a.xsrfCookieName]:void 0)&&(na[c.xsrfHeaderName||a.xsrfHeaderName]= +p),f(c.method,N,d,k,na,c.timeout,c.withCredentials,c.responseType,e(c.eventHandlers),e(c.uploadEventHandlers)));return P}function t(a,b){0=h&&(u.resolve(s), +f(D.$$intervalId));t||c.$apply()},k,u,t);return D}}}]}function zd(a,b){var d=la(a);b.$$protocol=d.protocol;b.$$host=d.hostname;b.$$port=da(d.port)||Ig[d.protocol]||null}function Ad(a,b,d){if(Jg.test(a))throw jb("badpath",a);var c="/"!==a.charAt(0);c&&(a="/"+a);a=la(a);for(var c=(c&&"/"===a.pathname.charAt(0)?a.pathname.substring(1):a.pathname).split("/"),e=c.length;e--;)c[e]=decodeURIComponent(c[e]),d&&(c[e]=c[e].replace(/\//g,"%2F"));d=c.join("/");b.$$path=d;b.$$search=fc(a.search);b.$$hash=decodeURIComponent(a.hash); +b.$$path&&"/"!==b.$$path.charAt(0)&&(b.$$path="/"+b.$$path)}function wc(a,b){return a.slice(0,b.length)===b}function wa(a,b){if(wc(b,a))return b.substr(a.length)}function qa(a){var b=a.indexOf("#");return-1===b?a:a.substr(0,b)}function xc(a,b,d){this.$$html5=!0;d=d||"";zd(a,this);this.$$parse=function(a){var d=wa(b,a);if(!C(d))throw jb("ipthprfx",a,b);Ad(d,this,!0);this.$$path||(this.$$path="/");this.$$compose()};this.$$normalizeUrl=function(a){return b+a.substr(1)};this.$$parseLinkUrl=function(c, +e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;v(f=wa(a,c))?(g=f,g=d&&v(f=wa(d,f))?b+(wa("/",f)||f):a+g):v(f=wa(b,c))?g=b+f:b===c+"/"&&(g=b);g&&this.$$parse(g);return!!g}}function yc(a,b,d){zd(a,this);this.$$parse=function(c){var e=wa(a,c)||wa(b,c),f;x(e)||"#"!==e.charAt(0)?this.$$html5?f=e:(f="",x(e)&&(a=c,this.replace())):(f=wa(d,e),x(f)&&(f=e));Ad(f,this,!1);c=this.$$path;var e=a,g=/^\/[A-Z]:(\/.*)/;wc(f,e)&&(f=f.replace(e,""));g.exec(f)||(c=(f=g.exec(c))?f[1]:c);this.$$path=c;this.$$compose()}; +this.$$normalizeUrl=function(b){return a+(b?d+b:"")};this.$$parseLinkUrl=function(b,d){return qa(a)===qa(b)?(this.$$parse(b),!0):!1}}function Bd(a,b,d){this.$$html5=!0;yc.apply(this,arguments);this.$$parseLinkUrl=function(c,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;a===qa(c)?f=c:(g=wa(b,c))?f=a+d+g:b===c+"/"&&(f=b);f&&this.$$parse(f);return!!f};this.$$normalizeUrl=function(b){return a+d+b}}function Lb(a){return function(){return this[a]}}function Cd(a,b){return function(d){if(x(d))return this[a]; +this[a]=b(d);this.$$compose();return this}}function Pf(){var a="!",b={enabled:!1,requireBase:!0,rewriteLinks:!0};this.hashPrefix=function(b){return v(b)?(a=b,this):a};this.html5Mode=function(a){if(Fa(a))return b.enabled=a,this;if(F(a)){Fa(a.enabled)&&(b.enabled=a.enabled);Fa(a.requireBase)&&(b.requireBase=a.requireBase);if(Fa(a.rewriteLinks)||C(a.rewriteLinks))b.rewriteLinks=a.rewriteLinks;return this}return b};this.$get=["$rootScope","$browser","$sniffer","$rootElement","$window",function(d,c,e, +f,g){function k(a,b){return a===b||la(a).href===la(b).href}function h(a,b,d){var e=m.url(),f=m.$$state;try{c.url(a,b,d),m.$$state=c.state()}catch(g){throw m.url(e),m.$$state=f,g;}}function l(a,b){d.$broadcast("$locationChangeSuccess",m.absUrl(),a,m.$$state,b)}var m,q;q=c.baseHref();var n=c.url(),s;if(b.enabled){if(!q&&b.requireBase)throw jb("nobase");s=n.substring(0,n.indexOf("/",n.indexOf("//")+2))+(q||"/");q=e.history?xc:Bd}else s=qa(n),q=yc;var t=s.substr(0,qa(s).lastIndexOf("/")+1);m=new q(s, +t,"#"+a);m.$$parseLinkUrl(n,n);m.$$state=c.state();var u=/^\s*(javascript|mailto):/i;f.on("click",function(a){var e=b.rewriteLinks;if(e&&!a.ctrlKey&&!a.metaKey&&!a.shiftKey&&2!==a.which&&2!==a.button){for(var g=y(a.target);"a"!==ta(g[0]);)if(g[0]===f[0]||!(g=g.parent())[0])return;if(!C(e)||!x(g.attr(e))){var e=g.prop("href"),h=g.attr("href")||g.attr("xlink:href");F(e)&&"[object SVGAnimatedString]"===e.toString()&&(e=la(e.animVal).href);u.test(e)||!e||g.attr("target")||a.isDefaultPrevented()||!m.$$parseLinkUrl(e, +h)||(a.preventDefault(),m.absUrl()!==c.url()&&d.$apply())}}});m.absUrl()!==n&&c.url(m.absUrl(),!0);var D=!0;c.onUrlChange(function(a,b){wc(a,t)?(d.$evalAsync(function(){var c=m.absUrl(),e=m.$$state,f;m.$$parse(a);m.$$state=b;f=d.$broadcast("$locationChangeStart",a,c,b,e).defaultPrevented;m.absUrl()===a&&(f?(m.$$parse(c),m.$$state=e,h(c,!1,e)):(D=!1,l(c,e)))}),d.$$phase||d.$digest()):g.location.href=a});d.$watch(function(){if(D||m.$$urlUpdatedByLocation){m.$$urlUpdatedByLocation=!1;var a=c.url(),b= +m.absUrl(),f=c.state(),g=m.$$replace,n=!k(a,b)||m.$$html5&&e.history&&f!==m.$$state;if(D||n)D=!1,d.$evalAsync(function(){var b=m.absUrl(),c=d.$broadcast("$locationChangeStart",b,a,m.$$state,f).defaultPrevented;m.absUrl()===b&&(c?(m.$$parse(a),m.$$state=f):(n&&h(b,g,f===m.$$state?null:m.$$state),l(a,f)))})}m.$$replace=!1});return m}]}function Qf(){var a=!0,b=this;this.debugEnabled=function(b){return v(b)?(a=b,this):a};this.$get=["$window",function(d){function c(a){bc(a)&&(a.stack&&f?a=a.message&&-1=== +a.stack.indexOf(a.message)?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function e(a){var b=d.console||{},e=b[a]||b.log||A;return function(){var a=[];r(arguments,function(b){a.push(c(b))});return Function.prototype.apply.call(e,b,a)}}var f=Aa||/\bEdge\//.test(d.navigator&&d.navigator.userAgent);return{log:e("log"),info:e("info"),warn:e("warn"),error:e("error"),debug:function(){var c=e("debug");return function(){a&&c.apply(b,arguments)}}()}}]} +function Kg(a){return a+""}function Lg(a,b){return"undefined"!==typeof a?a:b}function Dd(a,b){return"undefined"===typeof a?b:"undefined"===typeof b?a:a+b}function Mg(a,b){switch(a.type){case p.MemberExpression:if(a.computed)return!1;break;case p.UnaryExpression:return 1;case p.BinaryExpression:return"+"!==a.operator?1:!1;case p.CallExpression:return!1}return void 0===b?Ed:b}function Y(a,b,d){var c,e,f=a.isPure=Mg(a,d);switch(a.type){case p.Program:c=!0;r(a.body,function(a){Y(a.expression,b,f);c=c&& +a.expression.constant});a.constant=c;break;case p.Literal:a.constant=!0;a.toWatch=[];break;case p.UnaryExpression:Y(a.argument,b,f);a.constant=a.argument.constant;a.toWatch=a.argument.toWatch;break;case p.BinaryExpression:Y(a.left,b,f);Y(a.right,b,f);a.constant=a.left.constant&&a.right.constant;a.toWatch=a.left.toWatch.concat(a.right.toWatch);break;case p.LogicalExpression:Y(a.left,b,f);Y(a.right,b,f);a.constant=a.left.constant&&a.right.constant;a.toWatch=a.constant?[]:[a];break;case p.ConditionalExpression:Y(a.test, +b,f);Y(a.alternate,b,f);Y(a.consequent,b,f);a.constant=a.test.constant&&a.alternate.constant&&a.consequent.constant;a.toWatch=a.constant?[]:[a];break;case p.Identifier:a.constant=!1;a.toWatch=[a];break;case p.MemberExpression:Y(a.object,b,f);a.computed&&Y(a.property,b,f);a.constant=a.object.constant&&(!a.computed||a.property.constant);a.toWatch=a.constant?[]:[a];break;case p.CallExpression:c=d=a.filter?!b(a.callee.name).$stateful:!1;e=[];r(a.arguments,function(a){Y(a,b,f);c=c&&a.constant;e.push.apply(e, +a.toWatch)});a.constant=c;a.toWatch=d?e:[a];break;case p.AssignmentExpression:Y(a.left,b,f);Y(a.right,b,f);a.constant=a.left.constant&&a.right.constant;a.toWatch=[a];break;case p.ArrayExpression:c=!0;e=[];r(a.elements,function(a){Y(a,b,f);c=c&&a.constant;e.push.apply(e,a.toWatch)});a.constant=c;a.toWatch=e;break;case p.ObjectExpression:c=!0;e=[];r(a.properties,function(a){Y(a.value,b,f);c=c&&a.value.constant;e.push.apply(e,a.value.toWatch);a.computed&&(Y(a.key,b,!1),c=c&&a.key.constant,e.push.apply(e, +a.key.toWatch))});a.constant=c;a.toWatch=e;break;case p.ThisExpression:a.constant=!1;a.toWatch=[];break;case p.LocalsExpression:a.constant=!1,a.toWatch=[]}}function Fd(a){if(1===a.length){a=a[0].expression;var b=a.toWatch;return 1!==b.length?b:b[0]!==a?b:void 0}}function Gd(a){return a.type===p.Identifier||a.type===p.MemberExpression}function Hd(a){if(1===a.body.length&&Gd(a.body[0].expression))return{type:p.AssignmentExpression,left:a.body[0].expression,right:{type:p.NGValueParameter},operator:"="}} +function Id(a){this.$filter=a}function Jd(a){this.$filter=a}function Mb(a,b,d){this.ast=new p(a,d);this.astCompiler=d.csp?new Jd(b):new Id(b)}function zc(a){return z(a.valueOf)?a.valueOf():Ng.call(a)}function Rf(){var a=S(),b={"true":!0,"false":!1,"null":null,undefined:void 0},d,c;this.addLiteral=function(a,c){b[a]=c};this.setIdentifierFns=function(a,b){d=a;c=b;return this};this.$get=["$filter",function(e){function f(b,c){var d,f;switch(typeof b){case "string":return f=b=b.trim(),d=a[f],d||(d=new Nb(t), +d=(new Mb(d,e,t)).parse(b),a[f]=q(d)),s(d,c);case "function":return s(b,c);default:return s(A,c)}}function g(a,b,c){return null==a||null==b?a===b:"object"!==typeof a||(a=zc(a),"object"!==typeof a||c)?a===b||a!==a&&b!==b:!1}function k(a,b,c,d,e){var f=d.inputs,h;if(1===f.length){var k=g,f=f[0];return a.$watch(function(a){var b=f(a);g(b,k,f.isPure)||(h=d(a,void 0,void 0,[b]),k=b&&zc(b));return h},b,c,e)}for(var l=[],m=[],n=0,q=f.length;n=c.$$state.status&&e&&e.length&&a(function(){for(var a,c,f=0,g=e.length;fa)for(b in l++,f)sa.call(e,b)||(s--,delete f[b])}else f!==e&&(f=e,l++);return l}}c.$$pure=g(a).literal;c.$stateful=!c.$$pure;var d=this,e,f,h,k=1r&&(x=4-r,E[x]|| +(E[x]=[]),E[x].push({msg:z(a.exp)?"fn: "+(a.exp.name||a.exp.toString()):a.exp,newVal:g,oldVal:h}));else if(a===c){s=!1;break a}}catch(B){f(B)}if(!(n=!p.$$suspended&&p.$$watchersCount&&p.$$childHead||p!==D&&p.$$nextSibling))for(;p!==D&&!(n=p.$$nextSibling);)p=p.$parent}while(p=n);if((s||v.length)&&!r--)throw w.$$phase=null,d("infdig",b,E);}while(s||v.length);for(w.$$phase=null;GAa)throw Da("iequirks");var c=oa(U);c.isEnabled=function(){return a}; +c.trustAs=d.trustAs;c.getTrusted=d.getTrusted;c.valueOf=d.valueOf;a||(c.trustAs=c.getTrusted=function(a,b){return b},c.valueOf=Ta);c.parseAs=function(a,d){var e=b(d);return e.literal&&e.constant?e:b(d,function(b){return c.getTrusted(a,b)})};var e=c.parseAs,f=c.getTrusted,g=c.trustAs;r(U,function(a,b){var d=O(b);c[("parse_as_"+d).replace(Bc,wb)]=function(b){return e(a,b)};c[("get_trusted_"+d).replace(Bc,wb)]=function(b){return f(a,b)};c[("trust_as_"+d).replace(Bc,wb)]=function(b){return g(a,b)}}); +return c}]}function Xf(){this.$get=["$window","$document",function(a,b){var d={},c=!((!a.nw||!a.nw.process)&&a.chrome&&(a.chrome.app&&a.chrome.app.runtime||!a.chrome.app&&a.chrome.runtime&&a.chrome.runtime.id))&&a.history&&a.history.pushState,e=da((/android (\d+)/.exec(O((a.navigator||{}).userAgent))||[])[1]),f=/Boxee/i.test((a.navigator||{}).userAgent),g=b[0]||{},k=g.body&&g.body.style,h=!1,l=!1;k&&(h=!!("transition"in k||"webkitTransition"in k),l=!!("animation"in k||"webkitAnimation"in k));return{history:!(!c|| +4>e||f),hasEvent:function(a){if("input"===a&&Aa)return!1;if(x(d[a])){var b=g.createElement("div");d[a]="on"+a in b}return d[a]},csp:pa(),transitions:h,animations:l,android:e}}]}function Yf(){this.$get=ia(function(a){return new Pg(a)})}function Pg(a){function b(){var a=e.pop();return a&&a.cb}function d(a){for(var b=e.length-1;0<=b;--b){var c=e[b];if(c.type===a)return e.splice(b,1),c.cb}}var c={},e=[],f=this.ALL_TASKS_TYPE="$$all$$",g=this.DEFAULT_TASK_TYPE="$$default$$";this.completeTask=function(e, +h){h=h||g;try{e()}finally{var l;l=h||g;c[l]&&(c[l]--,c[f]--);l=c[h];var m=c[f];if(!m||!l)for(l=m?d:b;m=l(h);)try{m()}catch(q){a.error(q)}}};this.incTaskCount=function(a){a=a||g;c[a]=(c[a]||0)+1;c[f]=(c[f]||0)+1};this.notifyWhenNoPendingTasks=function(a,b){b=b||f;c[b]?e.push({type:b,cb:a}):a()}}function $f(){var a;this.httpOptions=function(b){return b?(a=b,this):a};this.$get=["$exceptionHandler","$templateCache","$http","$q","$sce",function(b,d,c,e,f){function g(k,h){g.totalPendingRequests++;if(!C(k)|| +x(d.get(k)))k=f.getTrustedResourceUrl(k);var l=c.defaults&&c.defaults.transformResponse;I(l)?l=l.filter(function(a){return a!==uc}):l===uc&&(l=null);return c.get(k,R({cache:d,transformResponse:l},a)).finally(function(){g.totalPendingRequests--}).then(function(a){return d.put(k,a.data)},function(a){h||(a=Qg("tpload",k,a.status,a.statusText),b(a));return e.reject(a)})}g.totalPendingRequests=0;return g}]}function ag(){this.$get=["$rootScope","$browser","$location",function(a,b,d){return{findBindings:function(a, +b,d){a=a.getElementsByClassName("ng-binding");var g=[];r(a,function(a){var c=ea.element(a).data("$binding");c&&r(c,function(c){d?(new RegExp("(^|\\s)"+Ld(b)+"(\\s|\\||$)")).test(c)&&g.push(a):-1!==c.indexOf(b)&&g.push(a)})});return g},findModels:function(a,b,d){for(var g=["ng-","data-ng-","ng\\:"],k=0;kc&&(c=e),c+=+a.slice(e+1),a= +a.substring(0,e)):0>c&&(c=a.length);for(e=0;a.charAt(e)===Dc;e++);if(e===(g=a.length))d=[0],c=1;else{for(g--;a.charAt(g)===Dc;)g--;c-=e;d=[];for(f=0;e<=g;e++,f++)d[f]=+a.charAt(e)}c>Vd&&(d=d.splice(0,Vd-1),b=c-1,c=1);return{d:d,e:b,i:c}}function Zg(a,b,d,c){var e=a.d,f=e.length-a.i;b=x(b)?Math.min(Math.max(d,f),c):+b;d=b+a.i;c=e[d];if(0d- +1){for(c=0;c>d;c--)e.unshift(0),a.i++;e.unshift(1);a.i++}else e[d-1]++;for(;fk;)h.unshift(0),k++;0=b.lgSize&&k.unshift(h.splice(-b.lgSize,h.length).join(""));h.length>b.gSize;)k.unshift(h.splice(-b.gSize,h.length).join(""));h.length&&k.unshift(h.join(""));h=k.join(d);f.length&&(h+=c+f.join(""));e&&(h+="e+"+e)}return 0>a&&!g?b.negPre+h+b.negSuf:b.posPre+h+b.posSuf}function Ob(a,b,d,c){var e="";if(0>a||c&&0>=a)c?a=-a+1:(a=-a,e="-");for(a=""+a;a.length-d)f+=d;0=== +f&&-12===d&&(f=12);return Ob(f,b,c,e)}}function kb(a,b,d){return function(c,e){var f=c["get"+a](),g=ub((d?"STANDALONE":"")+(b?"SHORT":"")+a);return e[g][f]}}function Wd(a){var b=(new Date(a,0,1)).getDay();return new Date(a,0,(4>=b?5:12)-b)}function Xd(a){return function(b){var d=Wd(b.getFullYear());b=+new Date(b.getFullYear(),b.getMonth(),b.getDate()+(4-b.getDay()))-+d;b=1+Math.round(b/6048E5);return Ob(b,a)}}function Ec(a,b){return 0>=a.getFullYear()?b.ERAS[0]:b.ERAS[1]}function Qd(a){function b(a){var b; +if(b=a.match(d)){a=new Date(0);var f=0,g=0,k=b[8]?a.setUTCFullYear:a.setFullYear,h=b[8]?a.setUTCHours:a.setHours;b[9]&&(f=da(b[9]+b[10]),g=da(b[9]+b[11]));k.call(a,da(b[1]),da(b[2])-1,da(b[3]));f=da(b[4]||0)-f;g=da(b[5]||0)-g;k=da(b[6]||0);b=Math.round(1E3*parseFloat("0."+(b[7]||0)));h.call(a,f,g,k,b)}return a}var d=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,d,f){var g="",k=[],h,l;d=d||"mediumDate";d=a.DATETIME_FORMATS[d]|| +d;C(c)&&(c=$g.test(c)?da(c):b(c));ba(c)&&(c=new Date(c));if(!ha(c)||!isFinite(c.getTime()))return c;for(;d;)(l=ah.exec(d))?(k=db(k,l,1),d=k.pop()):(k.push(d),d=null);var m=c.getTimezoneOffset();f&&(m=dc(f,m),c=ec(c,f,!0));r(k,function(b){h=bh[b];g+=h?h(c,a.DATETIME_FORMATS,m):"''"===b?"'":b.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function Tg(){return function(a,b){x(b)&&(b=2);return eb(a,b)}}function Ug(){return function(a,b,d){b=Infinity===Math.abs(Number(b))?Number(b):da(b);if(V(b))return a; +ba(a)&&(a=a.toString());if(!xa(a))return a;d=!d||isNaN(d)?0:da(d);d=0>d?Math.max(0,a.length+d):d;return 0<=b?Fc(a,d,d+b):0===d?Fc(a,b,a.length):Fc(a,Math.max(0,d+b),d)}}function Fc(a,b,d){return C(a)?a.slice(b,d):Ga.call(a,b,d)}function Sd(a){function b(b){return b.map(function(b){var c=1,d=Ta;if(z(b))d=b;else if(C(b)){if("+"===b.charAt(0)||"-"===b.charAt(0))c="-"===b.charAt(0)?-1:1,b=b.substring(1);if(""!==b&&(d=a(b),d.constant))var e=d(),d=function(a){return a[e]}}return{get:d,descending:c}})}function d(a){switch(typeof a){case "number":case "boolean":case "string":return!0; +default:return!1}}function c(a,b){var c=0,d=a.type,h=b.type;if(d===h){var h=a.value,l=b.value;"string"===d?(h=h.toLowerCase(),l=l.toLowerCase()):"object"===d&&(F(h)&&(h=a.index),F(l)&&(l=b.index));h!==l&&(c=hb||37<=b&&40>=b||m(a,this,this.value)});if(e.hasEvent("paste"))b.on("paste cut drop",m)}b.on("change",l);if(be[g]&&c.$$hasNativeValidators&&g===d.type)b.on("keydown wheel mousedown",function(a){if(!h){var b=this.validity,c=b.badInput,d=b.typeMismatch;h=f.defer(function(){h=null;b.badInput===c&&b.typeMismatch===d||l(a)})}});c.$render=function(){var a=c.$isEmpty(c.$viewValue)? +"":c.$viewValue;b.val()!==a&&b.val(a)}}function Qb(a,b){return function(d,c){var e,f;if(ha(d))return d;if(C(d)){'"'===d.charAt(0)&&'"'===d.charAt(d.length-1)&&(d=d.substring(1,d.length-1));if(ch.test(d))return new Date(d);a.lastIndex=0;if(e=a.exec(d))return e.shift(),f=c?{yyyy:c.getFullYear(),MM:c.getMonth()+1,dd:c.getDate(),HH:c.getHours(),mm:c.getMinutes(),ss:c.getSeconds(),sss:c.getMilliseconds()/1E3}:{yyyy:1970,MM:1,dd:1,HH:0,mm:0,ss:0,sss:0},r(e,function(a,c){cf.yyyy&&e.setFullYear(f.yyyy),e}return NaN}}function nb(a,b,d,c){return function(e,f,g,k,h,l,m){function q(a){return a&&!(a.getTime&&a.getTime()!==a.getTime())}function n(a){return v(a)&&!ha(a)?s(a)||void 0:a}function s(a,b){var c=k.$options.getOption("timezone");p&&p!==c&&(b=Rc(b,dc(p)));var e=d(a,b);!isNaN(e)&&c&&(e=ec(e,c));return e}Hc(e,f,g,k,a);Ra(e,f,g,k,h,l);var t="time"===a||"datetimelocal"===a,u,p;k.$parsers.push(function(c){if(k.$isEmpty(c))return null; +if(b.test(c))return s(c,u);k.$$parserName=a});k.$formatters.push(function(a){if(a&&!ha(a))throw ob("datefmt",a);if(q(a)){u=a;var b=k.$options.getOption("timezone");b&&(p=b,u=ec(u,b,!0));var d=c;t&&C(k.$options.getOption("timeSecondsFormat"))&&(d=c.replace("ss.sss",k.$options.getOption("timeSecondsFormat")).replace(/:$/,""));a=m("date")(a,d,b);t&&k.$options.getOption("timeStripZeroSeconds")&&(a=a.replace(/(?::00)?(?:\.000)?$/,""));return a}p=u=null;return""});if(v(g.min)||g.ngMin){var r;k.$validators.min= +function(a){return!q(a)||x(r)||d(a)>=r};g.$observe("min",function(a){r=n(a);k.$validate()})}if(v(g.max)||g.ngMax){var y;k.$validators.max=function(a){return!q(a)||x(y)||d(a)<=y};g.$observe("max",function(a){y=n(a);k.$validate()})}}}function Hc(a,b,d,c,e){(c.$$hasNativeValidators=F(b[0].validity))&&c.$parsers.push(function(a){var d=b.prop("validity")||{};if(d.badInput||d.typeMismatch)c.$$parserName=e;else return a})}function ce(a){a.$parsers.push(function(b){if(a.$isEmpty(b))return null;if(dh.test(b))return parseFloat(b); +a.$$parserName="number"});a.$formatters.push(function(b){if(!a.$isEmpty(b)){if(!ba(b))throw ob("numfmt",b);b=b.toString()}return b})}function Sa(a){v(a)&&!ba(a)&&(a=parseFloat(a));return V(a)?void 0:a}function Ic(a){var b=a.toString(),d=b.indexOf(".");return-1===d?-1a&&(a=/e-(\d+)$/.exec(b))?Number(a[1]):0:b.length-d-1}function de(a,b,d){a=Number(a);var c=(a|0)!==a,e=(b|0)!==b,f=(d|0)!==d;if(c||e||f){var g=c?Ic(a):0,k=e?Ic(b):0,h=f?Ic(d):0,g=Math.max(g,k,h),g=Math.pow(10,g);a*=g;b*=g;d*=g;c&& +(a=Math.round(a));e&&(b=Math.round(b));f&&(d=Math.round(d))}return 0===(a-b)%d}function ee(a,b,d,c,e){if(v(c)){a=a(c);if(!a.constant)throw ob("constexpr",d,c);return a(b)}return e}function Jc(a,b){function d(a,b){if(!a||!a.length)return[];if(!b||!b.length)return a;var c=[],d=0;a:for(;d(?:<\/\1>|)$/,lc=/<|&#?\w+;/,ig=/<([\w:-]+)/,jg=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,ja={option:[1,'"],thead:[1,"","
"],col:[2,"", +"
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ja.optgroup=ja.option;ja.tbody=ja.tfoot=ja.colgroup=ja.caption=ja.thead;ja.th=ja.td;var qg=B.Node.prototype.contains||function(a){return!!(this.compareDocumentPosition(a)&16)},Wa=W.prototype={ready:ed,toString:function(){var a=[];r(this,function(b){a.push(""+b)});return"["+a.join(", ")+"]"},eq:function(a){return 0<=a?y(this[a]):y(this[this.length+a])},length:0, +push:gh,sort:[].sort,splice:[].splice},Gb={};r("multiple selected checked disabled readOnly required open".split(" "),function(a){Gb[O(a)]=a});var ld={};r("input select option textarea button form details".split(" "),function(a){ld[a]=!0});var sd={ngMinlength:"minlength",ngMaxlength:"maxlength",ngMin:"min",ngMax:"max",ngPattern:"pattern",ngStep:"step"};r({data:qc,removeData:pc,hasData:function(a){for(var b in Ja[a.ng339])return!0;return!1},cleanData:function(a){for(var b=0,d=a.length;b/,tg=/^[^(]*\(\s*([^)]*)\)/m, +jh=/,/,kh=/^\s*(_?)(\S+?)\1\s*$/,rg=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,za=M("$injector");fb.$$annotate=function(a,b,d){var c;if("function"===typeof a){if(!(c=a.$inject)){c=[];if(a.length){if(b)throw C(d)&&d||(d=a.name||ug(a)),za("strictdi",d);b=nd(a);r(b[1].split(jh),function(a){a.replace(kh,function(a,b,d){c.push(d)})})}a.$inject=c}}else I(a)?(b=a.length-1,sb(a[b],"fn"),c=a.slice(0,b)):sb(a,"fn",!0);return c};var ge=M("$animate"),vf=function(){this.$get=A},wf=function(){var a=new Hb,b=[];this.$get= +["$$AnimateRunner","$rootScope",function(d,c){function e(a,b,c){var d=!1;b&&(b=C(b)?b.split(" "):I(b)?b:[],r(b,function(b){b&&(d=!0,a[b]=c)}));return d}function f(){r(b,function(b){var c=a.get(b);if(c){var d=vg(b.attr("class")),e="",f="";r(c,function(a,b){a!==!!d[b]&&(a?e+=(e.length?" ":"")+b:f+=(f.length?" ":"")+b)});r(b,function(a){e&&Db(a,e);f&&Cb(a,f)});a.delete(b)}});b.length=0}return{enabled:A,on:A,off:A,pin:A,push:function(g,k,h,l){l&&l();h=h||{};h.from&&g.css(h.from);h.to&&g.css(h.to);if(h.addClass|| +h.removeClass)if(k=h.addClass,l=h.removeClass,h=a.get(g)||{},k=e(h,k,!0),l=e(h,l,!1),k||l)a.set(g,h),b.push(g),1===b.length&&c.$$postDigest(f);g=new d;g.complete();return g}}}]},tf=["$provide",function(a){var b=this,d=null,c=null;this.$$registeredAnimations=Object.create(null);this.register=function(c,d){if(c&&"."!==c.charAt(0))throw ge("notcsel",c);var g=c+"-animation";b.$$registeredAnimations[c.substr(1)]=g;a.factory(g,d)};this.customFilter=function(a){1===arguments.length&&(c=z(a)?a:null);return c}; +this.classNameFilter=function(a){if(1===arguments.length&&(d=a instanceof RegExp?a:null)&&/[(\s|\/)]ng-animate[(\s|\/)]/.test(d.toString()))throw d=null,ge("nongcls","ng-animate");return d};this.$get=["$$animateQueue",function(a){function b(a,c,d){if(d){var e;a:{for(e=0;e <= >= && || ! = |".split(" "),function(a){Tb[a]=!0});var nh={n:"\n",f:"\f",r:"\r",t:"\t",v:"\v", +"'":"'",'"':'"'},Nb=function(a){this.options=a};Nb.prototype={constructor:Nb,lex:function(a){this.text=a;this.index=0;for(this.tokens=[];this.index=a&&"string"===typeof a},isWhitespace:function(a){return" "===a||"\r"===a|| +"\t"===a||"\n"===a||"\v"===a||"\u00a0"===a},isIdentifierStart:function(a){return this.options.isIdentifierStart?this.options.isIdentifierStart(a,this.codePointAt(a)):this.isValidIdentifierStart(a)},isValidIdentifierStart:function(a){return"a"<=a&&"z">=a||"A"<=a&&"Z">=a||"_"===a||"$"===a},isIdentifierContinue:function(a){return this.options.isIdentifierContinue?this.options.isIdentifierContinue(a,this.codePointAt(a)):this.isValidIdentifierContinue(a)},isValidIdentifierContinue:function(a,b){return this.isValidIdentifierStart(a, +b)||this.isNumber(a)},codePointAt:function(a){return 1===a.length?a.charCodeAt(0):(a.charCodeAt(0)<<10)+a.charCodeAt(1)-56613888},peekMultichar:function(){var a=this.text.charAt(this.index),b=this.peek();if(!b)return a;var d=a.charCodeAt(0),c=b.charCodeAt(0);return 55296<=d&&56319>=d&&56320<=c&&57343>=c?a+b:a},isExpOperator:function(a){return"-"===a||"+"===a||this.isNumber(a)},throwError:function(a,b,d){d=d||this.index;b=v(b)?"s "+b+"-"+this.index+" ["+this.text.substring(b,d)+"]":" "+d;throw Ya("lexerr", +a,b,this.text);},readNumber:function(){for(var a="",b=this.index;this.index","<=",">=");)a={type:p.BinaryExpression,operator:b.text,left:a,right:this.additive()};return a},additive:function(){for(var a= +this.multiplicative(),b;b=this.expect("+","-");)a={type:p.BinaryExpression,operator:b.text,left:a,right:this.multiplicative()};return a},multiplicative:function(){for(var a=this.unary(),b;b=this.expect("*","/","%");)a={type:p.BinaryExpression,operator:b.text,left:a,right:this.unary()};return a},unary:function(){var a;return(a=this.expect("+","-","!"))?{type:p.UnaryExpression,operator:a.text,prefix:!0,argument:this.unary()}:this.primary()},primary:function(){var a;this.expect("(")?(a=this.filterChain(), +this.consume(")")):this.expect("[")?a=this.arrayDeclaration():this.expect("{")?a=this.object():this.selfReferential.hasOwnProperty(this.peek().text)?a=Ha(this.selfReferential[this.consume().text]):this.options.literals.hasOwnProperty(this.peek().text)?a={type:p.Literal,value:this.options.literals[this.consume().text]}:this.peek().identifier?a=this.identifier():this.peek().constant?a=this.constant():this.throwError("not a primary expression",this.peek());for(var b;b=this.expect("(","[",".");)"("=== +b.text?(a={type:p.CallExpression,callee:a,arguments:this.parseArguments()},this.consume(")")):"["===b.text?(a={type:p.MemberExpression,object:a,property:this.expression(),computed:!0},this.consume("]")):"."===b.text?a={type:p.MemberExpression,object:a,property:this.identifier(),computed:!1}:this.throwError("IMPOSSIBLE");return a},filter:function(a){a=[a];for(var b={type:p.CallExpression,callee:this.identifier(),arguments:a,filter:!0};this.expect(":");)a.push(this.expression());return b},parseArguments:function(){var a= +[];if(")"!==this.peekToken().text){do a.push(this.filterChain());while(this.expect(","))}return a},identifier:function(){var a=this.consume();a.identifier||this.throwError("is not a valid identifier",a);return{type:p.Identifier,name:a.text}},constant:function(){return{type:p.Literal,value:this.consume().value}},arrayDeclaration:function(){var a=[];if("]"!==this.peekToken().text){do{if(this.peek("]"))break;a.push(this.expression())}while(this.expect(","))}this.consume("]");return{type:p.ArrayExpression, +elements:a}},object:function(){var a=[],b;if("}"!==this.peekToken().text){do{if(this.peek("}"))break;b={type:p.Property,kind:"init"};this.peek().constant?(b.key=this.constant(),b.computed=!1,this.consume(":"),b.value=this.expression()):this.peek().identifier?(b.key=this.identifier(),b.computed=!1,this.peek(":")?(this.consume(":"),b.value=this.expression()):b.value=b.key):this.peek("[")?(this.consume("["),b.key=this.expression(),this.consume("]"),b.computed=!0,this.consume(":"),b.value=this.expression()): +this.throwError("invalid key",this.peek());a.push(b)}while(this.expect(","))}this.consume("}");return{type:p.ObjectExpression,properties:a}},throwError:function(a,b){throw Ya("syntax",b.text,a,b.index+1,this.text,this.text.substring(b.index));},consume:function(a){if(0===this.tokens.length)throw Ya("ueoe",this.text);var b=this.expect(a);b||this.throwError("is unexpected, expecting ["+a+"]",this.peek());return b},peekToken:function(){if(0===this.tokens.length)throw Ya("ueoe",this.text);return this.tokens[0]}, +peek:function(a,b,d,c){return this.peekAhead(0,a,b,d,c)},peekAhead:function(a,b,d,c,e){if(this.tokens.length>a){a=this.tokens[a];var f=a.text;if(f===b||f===d||f===c||f===e||!(b||d||c||e))return a}return!1},expect:function(a,b,d,c){return(a=this.peek(a,b,d,c))?(this.tokens.shift(),a):!1},selfReferential:{"this":{type:p.ThisExpression},$locals:{type:p.LocalsExpression}}};var Ed=2;Id.prototype={compile:function(a){var b=this;this.state={nextId:0,filters:{},fn:{vars:[],body:[],own:{}},assign:{vars:[], +body:[],own:{}},inputs:[]};Y(a,b.$filter);var d="",c;this.stage="assign";if(c=Hd(a))this.state.computing="assign",d=this.nextId(),this.recurse(c,d),this.return_(d),d="fn.assign="+this.generateFunction("assign","s,v,l");c=Fd(a.body);b.stage="inputs";r(c,function(a,c){var d="fn"+c;b.state[d]={vars:[],body:[],own:{}};b.state.computing=d;var k=b.nextId();b.recurse(a,k);b.return_(k);b.state.inputs.push({name:d,isPure:a.isPure});a.watchId=c});this.state.computing="fn";this.stage="main";this.recurse(a); +a='"'+this.USE+" "+this.STRICT+'";\n'+this.filterPrefix()+"var fn="+this.generateFunction("fn","s,l,a,i")+d+this.watchFns()+"return fn;";a=(new Function("$filter","getStringValue","ifDefined","plus",a))(this.$filter,Kg,Lg,Dd);this.state=this.stage=void 0;return a},USE:"use",STRICT:"strict",watchFns:function(){var a=[],b=this.state.inputs,d=this;r(b,function(b){a.push("var "+b.name+"="+d.generateFunction(b.name,"s"));b.isPure&&a.push(b.name,".isPure="+JSON.stringify(b.isPure)+";")});b.length&&a.push("fn.inputs=["+ +b.map(function(a){return a.name}).join(",")+"];");return a.join("")},generateFunction:function(a,b){return"function("+b+"){"+this.varsPrefix(a)+this.body(a)+"};"},filterPrefix:function(){var a=[],b=this;r(this.state.filters,function(d,c){a.push(d+"=$filter("+b.escape(c)+")")});return a.length?"var "+a.join(",")+";":""},varsPrefix:function(a){return this.state[a].vars.length?"var "+this.state[a].vars.join(",")+";":""},body:function(a){return this.state[a].body.join("")},recurse:function(a,b,d,c,e, +f){var g,k,h=this,l,m,q;c=c||A;if(!f&&v(a.watchId))b=b||this.nextId(),this.if_("i",this.lazyAssign(b,this.computedMember("i",a.watchId)),this.lazyRecurse(a,b,d,c,e,!0));else switch(a.type){case p.Program:r(a.body,function(b,c){h.recurse(b.expression,void 0,void 0,function(a){k=a});c!==a.body.length-1?h.current().body.push(k,";"):h.return_(k)});break;case p.Literal:m=this.escape(a.value);this.assign(b,m);c(b||m);break;case p.UnaryExpression:this.recurse(a.argument,void 0,void 0,function(a){k=a});m= +a.operator+"("+this.ifDefined(k,0)+")";this.assign(b,m);c(m);break;case p.BinaryExpression:this.recurse(a.left,void 0,void 0,function(a){g=a});this.recurse(a.right,void 0,void 0,function(a){k=a});m="+"===a.operator?this.plus(g,k):"-"===a.operator?this.ifDefined(g,0)+a.operator+this.ifDefined(k,0):"("+g+")"+a.operator+"("+k+")";this.assign(b,m);c(m);break;case p.LogicalExpression:b=b||this.nextId();h.recurse(a.left,b);h.if_("&&"===a.operator?b:h.not(b),h.lazyRecurse(a.right,b));c(b);break;case p.ConditionalExpression:b= +b||this.nextId();h.recurse(a.test,b);h.if_(b,h.lazyRecurse(a.alternate,b),h.lazyRecurse(a.consequent,b));c(b);break;case p.Identifier:b=b||this.nextId();d&&(d.context="inputs"===h.stage?"s":this.assign(this.nextId(),this.getHasOwnProperty("l",a.name)+"?l:s"),d.computed=!1,d.name=a.name);h.if_("inputs"===h.stage||h.not(h.getHasOwnProperty("l",a.name)),function(){h.if_("inputs"===h.stage||"s",function(){e&&1!==e&&h.if_(h.isNull(h.nonComputedMember("s",a.name)),h.lazyAssign(h.nonComputedMember("s",a.name), +"{}"));h.assign(b,h.nonComputedMember("s",a.name))})},b&&h.lazyAssign(b,h.nonComputedMember("l",a.name)));c(b);break;case p.MemberExpression:g=d&&(d.context=this.nextId())||this.nextId();b=b||this.nextId();h.recurse(a.object,g,void 0,function(){h.if_(h.notNull(g),function(){a.computed?(k=h.nextId(),h.recurse(a.property,k),h.getStringValue(k),e&&1!==e&&h.if_(h.not(h.computedMember(g,k)),h.lazyAssign(h.computedMember(g,k),"{}")),m=h.computedMember(g,k),h.assign(b,m),d&&(d.computed=!0,d.name=k)):(e&& +1!==e&&h.if_(h.isNull(h.nonComputedMember(g,a.property.name)),h.lazyAssign(h.nonComputedMember(g,a.property.name),"{}")),m=h.nonComputedMember(g,a.property.name),h.assign(b,m),d&&(d.computed=!1,d.name=a.property.name))},function(){h.assign(b,"undefined")});c(b)},!!e);break;case p.CallExpression:b=b||this.nextId();a.filter?(k=h.filter(a.callee.name),l=[],r(a.arguments,function(a){var b=h.nextId();h.recurse(a,b);l.push(b)}),m=k+"("+l.join(",")+")",h.assign(b,m),c(b)):(k=h.nextId(),g={},l=[],h.recurse(a.callee, +k,g,function(){h.if_(h.notNull(k),function(){r(a.arguments,function(b){h.recurse(b,a.constant?void 0:h.nextId(),void 0,function(a){l.push(a)})});m=g.name?h.member(g.context,g.name,g.computed)+"("+l.join(",")+")":k+"("+l.join(",")+")";h.assign(b,m)},function(){h.assign(b,"undefined")});c(b)}));break;case p.AssignmentExpression:k=this.nextId();g={};this.recurse(a.left,void 0,g,function(){h.if_(h.notNull(g.context),function(){h.recurse(a.right,k);m=h.member(g.context,g.name,g.computed)+a.operator+k; +h.assign(b,m);c(b||m)})},1);break;case p.ArrayExpression:l=[];r(a.elements,function(b){h.recurse(b,a.constant?void 0:h.nextId(),void 0,function(a){l.push(a)})});m="["+l.join(",")+"]";this.assign(b,m);c(b||m);break;case p.ObjectExpression:l=[];q=!1;r(a.properties,function(a){a.computed&&(q=!0)});q?(b=b||this.nextId(),this.assign(b,"{}"),r(a.properties,function(a){a.computed?(g=h.nextId(),h.recurse(a.key,g)):g=a.key.type===p.Identifier?a.key.name:""+a.key.value;k=h.nextId();h.recurse(a.value,k);h.assign(h.member(b, +g,a.computed),k)})):(r(a.properties,function(b){h.recurse(b.value,a.constant?void 0:h.nextId(),void 0,function(a){l.push(h.escape(b.key.type===p.Identifier?b.key.name:""+b.key.value)+":"+a)})}),m="{"+l.join(",")+"}",this.assign(b,m));c(b||m);break;case p.ThisExpression:this.assign(b,"s");c(b||"s");break;case p.LocalsExpression:this.assign(b,"l");c(b||"l");break;case p.NGValueParameter:this.assign(b,"v"),c(b||"v")}},getHasOwnProperty:function(a,b){var d=a+"."+b,c=this.current().own;c.hasOwnProperty(d)|| +(c[d]=this.nextId(!1,a+"&&("+this.escape(b)+" in "+a+")"));return c[d]},assign:function(a,b){if(a)return this.current().body.push(a,"=",b,";"),a},filter:function(a){this.state.filters.hasOwnProperty(a)||(this.state.filters[a]=this.nextId(!0));return this.state.filters[a]},ifDefined:function(a,b){return"ifDefined("+a+","+this.escape(b)+")"},plus:function(a,b){return"plus("+a+","+b+")"},return_:function(a){this.current().body.push("return ",a,";")},if_:function(a,b,d){if(!0===a)b();else{var c=this.current().body; +c.push("if(",a,"){");b();c.push("}");d&&(c.push("else{"),d(),c.push("}"))}},not:function(a){return"!("+a+")"},isNull:function(a){return a+"==null"},notNull:function(a){return a+"!=null"},nonComputedMember:function(a,b){var d=/[^$_a-zA-Z0-9]/g;return/^[$_a-zA-Z][$_a-zA-Z0-9]*$/.test(b)?a+"."+b:a+'["'+b.replace(d,this.stringEscapeFn)+'"]'},computedMember:function(a,b){return a+"["+b+"]"},member:function(a,b,d){return d?this.computedMember(a,b):this.nonComputedMember(a,b)},getStringValue:function(a){this.assign(a, +"getStringValue("+a+")")},lazyRecurse:function(a,b,d,c,e,f){var g=this;return function(){g.recurse(a,b,d,c,e,f)}},lazyAssign:function(a,b){var d=this;return function(){d.assign(a,b)}},stringEscapeRegex:/[^ a-zA-Z0-9]/g,stringEscapeFn:function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)},escape:function(a){if(C(a))return"'"+a.replace(this.stringEscapeRegex,this.stringEscapeFn)+"'";if(ba(a))return a.toString();if(!0===a)return"true";if(!1===a)return"false";if(null===a)return"null"; +if("undefined"===typeof a)return"undefined";throw Ya("esc");},nextId:function(a,b){var d="v"+this.state.nextId++;a||this.current().vars.push(d+(b?"="+b:""));return d},current:function(){return this.state[this.state.computing]}};Jd.prototype={compile:function(a){var b=this;Y(a,b.$filter);var d,c;if(d=Hd(a))c=this.recurse(d);d=Fd(a.body);var e;d&&(e=[],r(d,function(a,c){var d=b.recurse(a);d.isPure=a.isPure;a.input=d;e.push(d);a.watchId=c}));var f=[];r(a.body,function(a){f.push(b.recurse(a.expression))}); +a=0===a.body.length?A:1===a.body.length?f[0]:function(a,b){var c;r(f,function(d){c=d(a,b)});return c};c&&(a.assign=function(a,b,d){return c(a,d,b)});e&&(a.inputs=e);return a},recurse:function(a,b,d){var c,e,f=this,g;if(a.input)return this.inputs(a.input,a.watchId);switch(a.type){case p.Literal:return this.value(a.value,b);case p.UnaryExpression:return e=this.recurse(a.argument),this["unary"+a.operator](e,b);case p.BinaryExpression:return c=this.recurse(a.left),e=this.recurse(a.right),this["binary"+ +a.operator](c,e,b);case p.LogicalExpression:return c=this.recurse(a.left),e=this.recurse(a.right),this["binary"+a.operator](c,e,b);case p.ConditionalExpression:return this["ternary?:"](this.recurse(a.test),this.recurse(a.alternate),this.recurse(a.consequent),b);case p.Identifier:return f.identifier(a.name,b,d);case p.MemberExpression:return c=this.recurse(a.object,!1,!!d),a.computed||(e=a.property.name),a.computed&&(e=this.recurse(a.property)),a.computed?this.computedMember(c,e,b,d):this.nonComputedMember(c, +e,b,d);case p.CallExpression:return g=[],r(a.arguments,function(a){g.push(f.recurse(a))}),a.filter&&(e=this.$filter(a.callee.name)),a.filter||(e=this.recurse(a.callee,!0)),a.filter?function(a,c,d,f){for(var q=[],n=0;n":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)>b(c,e,f,g);return d?{value:c}:c}},"binary<=":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)<=b(c,e,f,g);return d?{value:c}:c}},"binary>=":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)>=b(c,e,f,g);return d?{value:c}: +c}},"binary&&":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)&&b(c,e,f,g);return d?{value:c}:c}},"binary||":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)||b(c,e,f,g);return d?{value:c}:c}},"ternary?:":function(a,b,d,c){return function(e,f,g,k){e=a(e,f,g,k)?b(e,f,g,k):d(e,f,g,k);return c?{value:e}:e}},value:function(a,b){return function(){return b?{context:void 0,name:void 0,value:a}:a}},identifier:function(a,b,d){return function(c,e,f,g){c=e&&a in e?e:c;d&&1!==d&&c&&null==c[a]&&(c[a]= +{});e=c?c[a]:void 0;return b?{context:c,name:a,value:e}:e}},computedMember:function(a,b,d,c){return function(e,f,g,k){var h=a(e,f,g,k),l,m;null!=h&&(l=b(e,f,g,k),l+="",c&&1!==c&&h&&!h[l]&&(h[l]={}),m=h[l]);return d?{context:h,name:l,value:m}:m}},nonComputedMember:function(a,b,d,c){return function(e,f,g,k){e=a(e,f,g,k);c&&1!==c&&e&&null==e[b]&&(e[b]={});f=null!=e?e[b]:void 0;return d?{context:e,name:b,value:f}:f}},inputs:function(a,b){return function(d,c,e,f){return f?f[b]:a(d,c,e)}}};Mb.prototype= +{constructor:Mb,parse:function(a){a=this.getAst(a);var b=this.astCompiler.compile(a.ast),d=a.ast;b.literal=0===d.body.length||1===d.body.length&&(d.body[0].expression.type===p.Literal||d.body[0].expression.type===p.ArrayExpression||d.body[0].expression.type===p.ObjectExpression);b.constant=a.ast.constant;b.oneTime=a.oneTime;return b},getAst:function(a){var b=!1;a=a.trim();":"===a.charAt(0)&&":"===a.charAt(1)&&(b=!0,a=a.substring(2));return{ast:this.ast.ast(a),oneTime:b}}};var Da=M("$sce"),U={HTML:"html", +CSS:"css",MEDIA_URL:"mediaUrl",URL:"url",RESOURCE_URL:"resourceUrl",JS:"js"},Bc=/_([a-z])/g,Qg=M("$templateRequest"),Rg=M("$timeout"),$=B.document.createElement("a"),Nd=la(B.location.href),La;Od.$inject=["$document"];cd.$inject=["$provide"];var Vd=22,Ud=".",Dc="0";Pd.$inject=["$locale"];Rd.$inject=["$locale"];var bh={yyyy:ga("FullYear",4,0,!1,!0),yy:ga("FullYear",2,0,!0,!0),y:ga("FullYear",1,0,!1,!0),MMMM:kb("Month"),MMM:kb("Month",!0),MM:ga("Month",2,1),M:ga("Month",1,1),LLLL:kb("Month",!1,!0),dd:ga("Date", +2),d:ga("Date",1),HH:ga("Hours",2),H:ga("Hours",1),hh:ga("Hours",2,-12),h:ga("Hours",1,-12),mm:ga("Minutes",2),m:ga("Minutes",1),ss:ga("Seconds",2),s:ga("Seconds",1),sss:ga("Milliseconds",3),EEEE:kb("Day"),EEE:kb("Day",!0),a:function(a,b){return 12>a.getHours()?b.AMPMS[0]:b.AMPMS[1]},Z:function(a,b,d){a=-1*d;return a=(0<=a?"+":"")+(Ob(Math[0=a.getFullYear()?b.ERANAMES[0]:b.ERANAMES[1]}}, +ah=/((?:[^yMLdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|m+|s+|a|Z|G+|w+))([\s\S]*)/,$g=/^-?\d+$/;Qd.$inject=["$locale"];var Vg=ia(O),Wg=ia(ub);Sd.$inject=["$parse"];var Je=ia({restrict:"E",compile:function(a,b){if(!b.href&&!b.xlinkHref)return function(a,b){if("a"===b[0].nodeName.toLowerCase()){var e="[object SVGAnimatedString]"===ma.call(b.prop("href"))?"xlink:href":"href";b.on("click",function(a){b.attr(e)||a.preventDefault()})}}}}),vb={};r(Gb,function(a,b){function d(a,d,e){a.$watch(e[c], +function(a){e.$set(b,!!a)})}if("multiple"!==a){var c=va("ng-"+b),e=d;"checked"===a&&(e=function(a,b,e){e.ngModel!==e[c]&&d(a,b,e)});vb[c]=function(){return{restrict:"A",priority:100,link:e}}}});r(sd,function(a,b){vb[b]=function(){return{priority:100,link:function(a,c,e){if("ngPattern"===b&&"/"===e.ngPattern.charAt(0)&&(c=e.ngPattern.match(fh))){e.$set("ngPattern",new RegExp(c[1],c[2]));return}a.$watch(e[b],function(a){e.$set(b,a)})}}}});r(["src","srcset","href"],function(a){var b=va("ng-"+a);vb[b]= +function(){return{priority:99,link:function(d,c,e){var f=a,g=a;"href"===a&&"[object SVGAnimatedString]"===ma.call(c.prop("href"))&&(g="xlinkHref",e.$attr[g]="xlink:href",f=null);e.$observe(b,function(b){b?(e.$set(g,b),Aa&&f&&c.prop(f,e[g])):"href"===a&&e.$set(g,null)})}}}});var lb={$addControl:A,$getControls:ia([]),$$renameControl:function(a,b){a.$name=b},$removeControl:A,$setValidity:A,$setDirty:A,$setPristine:A,$setSubmitted:A,$$setSubmitted:A};Pb.$inject=["$element","$attrs","$scope","$animate", +"$interpolate"];Pb.prototype={$rollbackViewValue:function(){r(this.$$controls,function(a){a.$rollbackViewValue()})},$commitViewValue:function(){r(this.$$controls,function(a){a.$commitViewValue()})},$addControl:function(a){Qa(a.$name,"input");this.$$controls.push(a);a.$name&&(this[a.$name]=a);a.$$parentForm=this},$getControls:function(){return oa(this.$$controls)},$$renameControl:function(a,b){var d=a.$name;this[d]===a&&delete this[d];this[b]=a;a.$name=b},$removeControl:function(a){a.$name&&this[a.$name]=== +a&&delete this[a.$name];r(this.$pending,function(b,d){this.$setValidity(d,null,a)},this);r(this.$error,function(b,d){this.$setValidity(d,null,a)},this);r(this.$$success,function(b,d){this.$setValidity(d,null,a)},this);cb(this.$$controls,a);a.$$parentForm=lb},$setDirty:function(){this.$$animate.removeClass(this.$$element,Za);this.$$animate.addClass(this.$$element,Ub);this.$dirty=!0;this.$pristine=!1;this.$$parentForm.$setDirty()},$setPristine:function(){this.$$animate.setClass(this.$$element,Za,Ub+ +" ng-submitted");this.$dirty=!1;this.$pristine=!0;this.$submitted=!1;r(this.$$controls,function(a){a.$setPristine()})},$setUntouched:function(){r(this.$$controls,function(a){a.$setUntouched()})},$setSubmitted:function(){for(var a=this;a.$$parentForm&&a.$$parentForm!==lb;)a=a.$$parentForm;a.$$setSubmitted()},$$setSubmitted:function(){this.$$animate.addClass(this.$$element,"ng-submitted");this.$submitted=!0;r(this.$$controls,function(a){a.$$setSubmitted&&a.$$setSubmitted()})}};$d({clazz:Pb,set:function(a, +b,d){var c=a[b];c?-1===c.indexOf(d)&&c.push(d):a[b]=[d]},unset:function(a,b,d){var c=a[b];c&&(cb(c,d),0===c.length&&delete a[b])}});var he=function(a){return["$timeout","$parse",function(b,d){function c(a){return""===a?d('this[""]').assign:d(a).assign||A}return{name:"form",restrict:a?"EAC":"E",require:["form","^^?form"],controller:Pb,compile:function(d,f){d.addClass(Za).addClass(mb);var g=f.name?"name":a&&f.ngForm?"ngForm":!1;return{pre:function(a,d,e,f){var q=f[0];if(!("action"in e)){var n=function(b){a.$apply(function(){q.$commitViewValue(); +q.$setSubmitted()});b.preventDefault()};d[0].addEventListener("submit",n);d.on("$destroy",function(){b(function(){d[0].removeEventListener("submit",n)},0,!1)})}(f[1]||q.$$parentForm).$addControl(q);var s=g?c(q.$name):A;g&&(s(a,q),e.$observe(g,function(b){q.$name!==b&&(s(a,void 0),q.$$parentForm.$$renameControl(q,b),s=c(q.$name),s(a,q))}));d.on("$destroy",function(){q.$$parentForm.$removeControl(q);s(a,void 0);R(q,lb)})}}}}}]},Ke=he(),We=he(!0),ch=/^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-][0-2]\d:[0-5]\d|Z)$/, +oh=/^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i,ph=/^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/,dh=/^\s*(-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/,ie=/^(\d{4,})-(\d{2})-(\d{2})$/,je=/^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,Lc=/^(\d{4,})-W(\d\d)$/,ke=/^(\d{4,})-(\d\d)$/, +le=/^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,be=S();r(["date","datetime-local","month","time","week"],function(a){be[a]=!0});var me={text:function(a,b,d,c,e,f){Ra(a,b,d,c,e,f);Gc(c)},date:nb("date",ie,Qb(ie,["yyyy","MM","dd"]),"yyyy-MM-dd"),"datetime-local":nb("datetimelocal",je,Qb(je,"yyyy MM dd HH mm ss sss".split(" ")),"yyyy-MM-ddTHH:mm:ss.sss"),time:nb("time",le,Qb(le,["HH","mm","ss","sss"]),"HH:mm:ss.sss"),week:nb("week",Lc,function(a,b){if(ha(a))return a;if(C(a)){Lc.lastIndex=0;var d=Lc.exec(a); +if(d){var c=+d[1],e=+d[2],f=d=0,g=0,k=0,h=Wd(c),e=7*(e-1);b&&(d=b.getHours(),f=b.getMinutes(),g=b.getSeconds(),k=b.getMilliseconds());return new Date(c,0,h.getDate()+e,d,f,g,k)}}return NaN},"yyyy-Www"),month:nb("month",ke,Qb(ke,["yyyy","MM"]),"yyyy-MM"),number:function(a,b,d,c,e,f){Hc(a,b,d,c,"number");ce(c);Ra(a,b,d,c,e,f);var g,k;if(v(d.min)||d.ngMin)c.$validators.min=function(a,b){return c.$isEmpty(b)||x(g)||b>=g},d.$observe("min",function(a){g=Sa(a);c.$validate()});if(v(d.max)||d.ngMax)c.$validators.max= +function(a,b){return c.$isEmpty(b)||x(k)||b<=k},d.$observe("max",function(a){k=Sa(a);c.$validate()});if(v(d.step)||d.ngStep){var h;c.$validators.step=function(a,b){return c.$isEmpty(b)||x(h)||de(b,g||0,h)};d.$observe("step",function(a){h=Sa(a);c.$validate()})}},url:function(a,b,d,c,e,f){Ra(a,b,d,c,e,f);Gc(c);c.$validators.url=function(a,b){var d=a||b;return c.$isEmpty(d)||oh.test(d)}},email:function(a,b,d,c,e,f){Ra(a,b,d,c,e,f);Gc(c);c.$validators.email=function(a,b){var d=a||b;return c.$isEmpty(d)|| +ph.test(d)}},radio:function(a,b,d,c){var e=!d.ngTrim||"false"!==T(d.ngTrim);x(d.name)&&b.attr("name",++pb);b.on("change",function(a){var g;b[0].checked&&(g=d.value,e&&(g=T(g)),c.$setViewValue(g,a&&a.type))});c.$render=function(){var a=d.value;e&&(a=T(a));b[0].checked=a===c.$viewValue};d.$observe("value",c.$render)},range:function(a,b,d,c,e,f){function g(a,c){b.attr(a,d[a]);d.$observe(a,c)}function k(a){q=Sa(a);V(c.$modelValue)||(m?(a=b.val(),q>a&&(a=q,b.val(a)),c.$setViewValue(a)):c.$validate())} +function h(a){n=Sa(a);V(c.$modelValue)||(m?(a=b.val(),n=q},g("min",k));e&&(c.$validators.max=m?function(){return!0}:function(a,b){return c.$isEmpty(b)||x(n)||b<=n},g("max",h));f&&(c.$validators.step=m?function(){return!p.stepMismatch}:function(a,b){return c.$isEmpty(b)||x(s)||de(b,q||0,s)},g("step",l))},checkbox:function(a,b,d,c,e,f,g,k){var h=ee(k,a,"ngTrueValue",d.ngTrueValue,!0),l=ee(k,a,"ngFalseValue",d.ngFalseValue,!1);b.on("change",function(a){c.$setViewValue(b[0].checked, +a&&a.type)});c.$render=function(){b[0].checked=c.$viewValue};c.$isEmpty=function(a){return!1===a};c.$formatters.push(function(a){return ua(a,h)});c.$parsers.push(function(a){return a?h:l})},hidden:A,button:A,submit:A,reset:A,file:A},Xc=["$browser","$sniffer","$filter","$parse",function(a,b,d,c){return{restrict:"E",require:["?ngModel"],link:{pre:function(e,f,g,k){k[0]&&(me[O(g.type)]||me.text)(e,f,g,k[0],b,a,d,c)}}}}],qh=/^(true|false|\d+)$/,pf=function(){function a(a,d,c){var e=v(c)?c:9===Aa?"":null; +a.prop("value",e);d.$set("value",c)}return{restrict:"A",priority:100,compile:function(b,d){return qh.test(d.ngValue)?function(b,d,f){b=b.$eval(f.ngValue);a(d,f,b)}:function(b,d,f){b.$watch(f.ngValue,function(b){a(d,f,b)})}}}},Oe=["$compile",function(a){return{restrict:"AC",compile:function(b){a.$$addBindingClass(b);return function(b,c,e){a.$$addBindingInfo(c,e.ngBind);c=c[0];b.$watch(e.ngBind,function(a){c.textContent=hc(a)})}}}}],Qe=["$interpolate","$compile",function(a,b){return{compile:function(d){b.$$addBindingClass(d); +return function(c,d,f){c=a(d.attr(f.$attr.ngBindTemplate));b.$$addBindingInfo(d,c.expressions);d=d[0];f.$observe("ngBindTemplate",function(a){d.textContent=x(a)?"":a})}}}}],Pe=["$sce","$parse","$compile",function(a,b,d){return{restrict:"A",compile:function(c,e){var f=b(e.ngBindHtml),g=b(e.ngBindHtml,function(b){return a.valueOf(b)});d.$$addBindingClass(c);return function(b,c,e){d.$$addBindingInfo(c,e.ngBindHtml);b.$watch(g,function(){var d=f(b);c.html(a.getTrustedHtml(d)||"")})}}}}],of=ia({restrict:"A", +require:"ngModel",link:function(a,b,d,c){c.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),Re=Jc("",!0),Te=Jc("Odd",0),Se=Jc("Even",1),Ue=Na({compile:function(a,b){b.$set("ngCloak",void 0);a.removeClass("ng-cloak")}}),Ve=[function(){return{restrict:"A",scope:!0,controller:"@",priority:500}}],bd={},rh={blur:!0,focus:!0};r("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "),function(a){var b= +va("ng-"+a);bd[b]=["$parse","$rootScope","$exceptionHandler",function(d,c,e){return pd(d,c,e,b,a,rh[a])}]});var Ye=["$animate","$compile",function(a,b){return{multiElement:!0,transclude:"element",priority:600,terminal:!0,restrict:"A",$$tlb:!0,link:function(d,c,e,f,g){var k,h,l;d.$watch(e.ngIf,function(d){d?h||g(function(d,f){h=f;d[d.length++]=b.$$createComment("end ngIf",e.ngIf);k={clone:d};a.enter(d,c.parent(),c)}):(l&&(l.remove(),l=null),h&&(h.$destroy(),h=null),k&&(l=tb(k.clone),a.leave(l).done(function(a){!1!== +a&&(l=null)}),k=null))})}}}],Ze=["$templateRequest","$anchorScroll","$animate",function(a,b,d){return{restrict:"ECA",priority:400,terminal:!0,transclude:"element",controller:ea.noop,compile:function(c,e){var f=e.ngInclude||e.src,g=e.onload||"",k=e.autoscroll;return function(c,e,m,q,n){var s=0,p,r,D,w=function(){r&&(r.remove(),r=null);p&&(p.$destroy(),p=null);D&&(d.leave(D).done(function(a){!1!==a&&(r=null)}),r=D,D=null)};c.$watch(f,function(f){var m=function(a){!1===a||!v(k)||k&&!c.$eval(k)||b()}, +r=++s;f?(a(f,!0).then(function(a){if(!c.$$destroyed&&r===s){var b=c.$new();q.template=a;a=n(b,function(a){w();d.enter(a,null,e).done(m)});p=b;D=a;p.$emit("$includeContentLoaded",f);c.$eval(g)}},function(){c.$$destroyed||r!==s||(w(),c.$emit("$includeContentError",f))}),c.$emit("$includeContentRequested",f)):(w(),q.template=null)})}}}}],rf=["$compile",function(a){return{restrict:"ECA",priority:-400,require:"ngInclude",link:function(b,d,c,e){ma.call(d[0]).match(/SVG/)?(d.empty(),a(dd(e.template,B.document).childNodes)(b, +function(a){d.append(a)},{futureParentElement:d})):(d.html(e.template),a(d.contents())(b))}}}],$e=Na({priority:450,compile:function(){return{pre:function(a,b,d){a.$eval(d.ngInit)}}}}),nf=function(){return{restrict:"A",priority:100,require:"ngModel",link:function(a,b,d,c){var e=d.ngList||", ",f="false"!==d.ngTrim,g=f?T(e):e;c.$parsers.push(function(a){if(!x(a)){var b=[];a&&r(a.split(g),function(a){a&&b.push(f?T(a):a)});return b}});c.$formatters.push(function(a){if(I(a))return a.join(e)});c.$isEmpty= +function(a){return!a||!a.length}}}},mb="ng-valid",Zd="ng-invalid",Za="ng-pristine",Ub="ng-dirty",ob=M("ngModel");Rb.$inject="$scope $exceptionHandler $attrs $element $parse $animate $timeout $q $interpolate".split(" ");Rb.prototype={$$initGetterSetters:function(){if(this.$options.getOption("getterSetter")){var a=this.$$parse(this.$$attr.ngModel+"()"),b=this.$$parse(this.$$attr.ngModel+"($$$p)");this.$$ngModelGet=function(b){var c=this.$$parsedNgModel(b);z(c)&&(c=a(b));return c};this.$$ngModelSet= +function(a,c){z(this.$$parsedNgModel(a))?b(a,{$$$p:c}):this.$$parsedNgModelAssign(a,c)}}else if(!this.$$parsedNgModel.assign)throw ob("nonassign",this.$$attr.ngModel,ya(this.$$element));},$render:A,$isEmpty:function(a){return x(a)||""===a||null===a||a!==a},$$updateEmptyClasses:function(a){this.$isEmpty(a)?(this.$$animate.removeClass(this.$$element,"ng-not-empty"),this.$$animate.addClass(this.$$element,"ng-empty")):(this.$$animate.removeClass(this.$$element,"ng-empty"),this.$$animate.addClass(this.$$element, +"ng-not-empty"))},$setPristine:function(){this.$dirty=!1;this.$pristine=!0;this.$$animate.removeClass(this.$$element,Ub);this.$$animate.addClass(this.$$element,Za)},$setDirty:function(){this.$dirty=!0;this.$pristine=!1;this.$$animate.removeClass(this.$$element,Za);this.$$animate.addClass(this.$$element,Ub);this.$$parentForm.$setDirty()},$setUntouched:function(){this.$touched=!1;this.$untouched=!0;this.$$animate.setClass(this.$$element,"ng-untouched","ng-touched")},$setTouched:function(){this.$touched= +!0;this.$untouched=!1;this.$$animate.setClass(this.$$element,"ng-touched","ng-untouched")},$rollbackViewValue:function(){this.$$timeout.cancel(this.$$pendingDebounce);this.$viewValue=this.$$lastCommittedViewValue;this.$render()},$validate:function(){if(!V(this.$modelValue)){var a=this.$$lastCommittedViewValue,b=this.$$rawModelValue,d=this.$valid,c=this.$modelValue,e=this.$options.getOption("allowInvalid"),f=this;this.$$runValidators(b,a,function(a){e||d===a||(f.$modelValue=a?b:void 0,f.$modelValue!== +c&&f.$$writeModelToScope())})}},$$runValidators:function(a,b,d){function c(){var c=!0;r(h.$validators,function(d,e){var g=Boolean(d(a,b));c=c&&g;f(e,g)});return c?!0:(r(h.$asyncValidators,function(a,b){f(b,null)}),!1)}function e(){var c=[],d=!0;r(h.$asyncValidators,function(e,g){var h=e(a,b);if(!h||!z(h.then))throw ob("nopromise",h);f(g,void 0);c.push(h.then(function(){f(g,!0)},function(){d=!1;f(g,!1)}))});c.length?h.$$q.all(c).then(function(){g(d)},A):g(!0)}function f(a,b){k===h.$$currentValidationRunId&& +h.$setValidity(a,b)}function g(a){k===h.$$currentValidationRunId&&d(a)}this.$$currentValidationRunId++;var k=this.$$currentValidationRunId,h=this;(function(){var a=h.$$parserName;if(x(h.$$parserValid))f(a,null);else return h.$$parserValid||(r(h.$validators,function(a,b){f(b,null)}),r(h.$asyncValidators,function(a,b){f(b,null)})),f(a,h.$$parserValid),h.$$parserValid;return!0})()?c()?e():g(!1):g(!1)},$commitViewValue:function(){var a=this.$viewValue;this.$$timeout.cancel(this.$$pendingDebounce);if(this.$$lastCommittedViewValue!== +a||""===a&&this.$$hasNativeValidators)this.$$updateEmptyClasses(a),this.$$lastCommittedViewValue=a,this.$pristine&&this.$setDirty(),this.$$parseAndValidate()},$$parseAndValidate:function(){var a=this.$$lastCommittedViewValue,b=this;this.$$parserValid=x(a)?void 0:!0;this.$setValidity(this.$$parserName,null);this.$$parserName="parse";if(this.$$parserValid)for(var d=0;de||c.$isEmpty(b)|| +b.length<=e}}}}},$c=function(){return{restrict:"A",require:"?ngModel",link:function(a,b,d,c){if(c){var e=0;d.$observe("minlength",function(a){e=da(a)||0;c.$validate()});c.$validators.minlength=function(a,b){return c.$isEmpty(b)||b.length>=e}}}}};B.angular.bootstrap?B.console&&console.log("WARNING: Tried to load AngularJS more than once."):(Ce(),Ge(ea),ea.module("ngLocale",[],["$provide",function(a){function b(a){a+="";var b=a.indexOf(".");return-1==b?0:a.length-b-1}a.value("$locale",{DATETIME_FORMATS:{AMPMS:["AM", +"PM"],DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),ERANAMES:["Before Christ","Anno Domini"],ERAS:["BC","AD"],FIRSTDAYOFWEEK:6,MONTH:"January February March April May June July August September October November December".split(" "),SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "),SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),STANDALONEMONTH:"January February March April May June July August September October November December".split(" "),WEEKENDRANGE:[5, +6],fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",medium:"MMM d, y h:mm:ss a",mediumDate:"MMM d, y",mediumTime:"h:mm:ss a","short":"M/d/yy h:mm a",shortDate:"M/d/yy",shortTime:"h:mm a"},NUMBER_FORMATS:{CURRENCY_SYM:"$",DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{gSize:3,lgSize:3,maxFrac:3,minFrac:0,minInt:1,negPre:"-",negSuf:"",posPre:"",posSuf:""},{gSize:3,lgSize:3,maxFrac:2,minFrac:2,minInt:1,negPre:"-\u00a4",negSuf:"",posPre:"\u00a4",posSuf:""}]},id:"en-us",localeID:"en_US",pluralCat:function(a, +c){var e=a|0,f=c;void 0===f&&(f=Math.min(b(a),3));Math.pow(10,f);return 1==e&&0==f?"one":"other"}})}]),y(function(){xe(B.document,Tc)}))})(window);!window.angular.$$csp().noInlineStyle&&window.angular.element(document.head).prepend(''); +//# sourceMappingURL=angular.min.js.map \ No newline at end of file diff --git a/app/listen1_chrome_extension/js/vendor/jquery-3.3.1.min.js b/app/listen1_chrome_extension/js/vendor/jquery-3.3.1.min.js new file mode 100644 index 0000000..49d1fcf --- /dev/null +++ b/app/listen1_chrome_extension/js/vendor/jquery-3.3.1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){"use strict";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return"function"==typeof t&&"number"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement("script");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[c.call(e)]||"object":typeof e}var b="3.3.1",w=function(e,t){return new w.fn.init(e,t)},T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;w.fn=w.prototype={jquery:"3.3.1",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;while(s--)h[s]="#"+c+" "+ve(h[s]);v=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||y.push("~="),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||y.push(".#.+[+~]")}),ue(function(e){e.innerHTML="";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),v.push("!=",W)}),y=y.length&&new RegExp(y.join("|")),v=v.length&&new RegExp(v.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,"iframe")?e.contentDocument:(N(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener("DOMContentLoaded",_),e.removeEventListener("load",_),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",_),e.addEventListener("load",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(M)||[""]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||"").match(M)||[""]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,Ae=/\s*$/g;function Le(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n1&&"string"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,"script"),He)).length;f")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r0&&ve(a,!u&&ye(e,"script")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[s]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===w.css(e,"boxSizing",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?"":"px")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}},tt.prototype.init.prototype=tt.prototype,tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&N(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(" ")}function mt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=mt(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+vt(mt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,"type")?t.type:t,x=f.call(t,"namespace")?t.namespace.split("."):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(x=m.split(".")).shift(),x.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+x.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,"events")||{})[t.type]&&J.get(s,"handle"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\?/;w.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||w.error("Invalid XML: "+t),n};var St=/\[\]$/,Dt=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,"\r\n")}}):{name:t.name,value:n.replace(Dt,"\r\n")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Bt=r.createElement("a");Bt.href=Ct.href;function Ft(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks("once memory"),x=h.statusCode||{},b={},T={},C="canceled",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(M)||[""],null==h.crossDomain){l=r.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+"//"+Bt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(qt,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(kt.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,"$1"),d=(kt.test(o)?"&":"?")+"_="+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader("If-Modified-Since",w.lastModified[o]),w.etag[o]&&E.setRequestHeader("If-None-Match",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader("Content-Type",h.contentType),E.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+$t+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C="abort",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger("ajaxSend",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort("timeout")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||"",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader("Last-Modified"))&&(w.lastModified[o]=T),(T=E.getResponseHeader("etag"))&&(w.etag[o]=T)),204===t||"HEAD"===h.type?C="nocontent":304===t?C="notmodified":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C="error",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+"",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?"ajaxSuccess":"ajaxError",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger("ajaxComplete",[E,h]),--w.active||w.event.trigger("ajaxStop")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,t){return w.get(e,void 0,t,"script")}}),w.each(["get","post"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&"withCredentials"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),w.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w(" - + + + @@ -35,11 +33,9 @@ - - @@ -47,485 +43,461 @@ - - + - -
- -
-
-
{{ dialog_title }} ×
-
- - -
    -
  • - -

    新建歌单

    -
  • -
  • - -

    {{ playlist.info.title }}

    -
  • -
- - -
- - - -
- - - - - -
-
- - -
-
- - -
- - - - -
- -
-

正在打开Last.fm页面...

-

请在打开的页面点击"Yes, all access", 允许Listen 1访问你的账户。

-
- - -
-
- - -
-
- - -
- - - -
- -
    -
  • - -

    {{ playlist.info.title }}

    -
  • -
+ +
+
+
+
+ +
+
+
{{ dialog_title }}×
+
+ +
    +
  • +

    {{_CREATE_PLAYLIST}}

    +
  • +
  • +

    {{ playlist.info.title }}

    +
  • +
+ +
+ + + +
+ +
+
+ + +
+
+ + +
+ + + +
+
+

{{_OPENING_LASTFM_PAGE}}

+

{{_CONFIRM_NOTICE_LASTFM}}

+
+ + +
+
+ +
+
+ + +
+ + +
+
    +
  • +

    {{ playlist.info.title }}

    +
  • +
+
+

{{_OPENING_GITHUB_PAGE}}

+

{{_CONFIRM_NOTICE_GITHUB}}

+
+ + +
+
+
    +
  • +

    {{_CREATE_PLAYLIST_BACKUP}}

    +
  • +
  • +

    {{ backup.id }}
    {{backup.description}}

    -
    -

    正在打开Github.com页面...

    -

    请在打开的页面点击"Authencate", 允许Listen 1访问你的账户。

    -
    - - +
  • +
+ +
+ + + +
+
    +
  • +

    {{ backup.id }} {{backup.description}}

    +
  • +
+
-
- -
    -
  • - -

    新建歌单备份

    -
  • -
  • - -

    {{ backup.id }} {{backup.description}}

    -
  • -
- - -
- - - -
- -
    -
  • - -

    {{ backup.id }} {{backup.description}}

    -
  • -
- -
-
- -
-
- -

Listen 1

- -
-
+
+ +
+ +
+ +
+
+
{{_NETEASE_MUSIC}}
+
+
{{_XIAMI_MUSIC}}
+
+
{{_QQ_MUSIC}}
+
+
{{_KUGOU_MUSIC}}
+
+
{{_KUWO_MUSIC}}
+
+
{{_BILIBILI_MUSIC}}
+
- -
-
- -
-
打开歌单
-
-
-
-
-
- -
-
-
-
+ + - -
-
- -
-
网易
- -
腾讯
- -
酷狗
-
酷我
-
哔哩
-
-
-
-
-
    -
  • -
    - - -
    - -
    + +
    +
    +
    +
    {{_LANGUAGE}}
    +
    +
    + +
    - +
    {{_BACKUP_PLAYLIST}}
    +
    +

    {{_BACKUP_WARNING}}

    +
    + +
    -
  • -
    - +
    +
    {{_RECOVER_PLAYLIST}}
    +
    +

    {{_RECOVER_WARNING}}

    + + +
    + +
    {{_CONNECT_TO_GITHUB}}
    +
    +
    +

    {{_STATUS}}:{{ github.getStatusText() }}

    + + + +
    +
    + +
    {{_SHORTCUTS}}
    +
    + +
    + + + {{_GLOBAL_SHORTCUTS_NOTICE}} +
    +
    +
    {{_CONNECT_TO_LASTFM}}
    +
    +
    +

    {{_STATUS}}:{{ lastfm.getStatusText() }}

    + + + +
    +
    + +
    {{_ABOUT}}
    +
    +

    Listen 1 {{_HOMEPAGE}}: http://listen1.github.io/listen1/

    +

    Listen 1 {{_EMAIL}}: githublisten1@gmail.com

    +

    {{_DESIGNER}}: iparanoid

    +

    {{_VERSION}}: 2.1.0 {{_LICENSE_NOTICE}}

    +
- -
-
-
- - - - -
- - - -
-
-
- -
导出我的歌单
-
-

重装插件或清除缓存数据会导致我的歌单数据丢失,强烈建议在这些操作前,备份我的歌单。

-
- - -
-
-
导入我的歌单
-
-

选择备份文件,恢复我的歌单。注意:恢复我的歌单会覆盖现有的歌单。

- - -
- -
连接到 Github.com
-
-
-

状态:{{ github.getStatusText() }}

- - - -
-
- -
快捷键
-
-
- -
-
-
连接到 Last.fm
-
-
-

状态:{{ lastfm.getStatusText() }}

- - - -
-
- -
关于
-
-

Listen 1 Fluent 修改版主页: https://github.com/oyrx/listen1_desktop_fluent

-

Listen 1 邮箱: rey@pku.edu.cn

-

Listen 1 原主页: http://listen1.github.io/listen1/

-

Listen 1 邮箱: githublisten1@gmail.com

-

当前版本 1.9.0 (本软件基于MIT协议开源免费)

-
-
-
-
- -
-
-
- × -
-
-
-
+ +
-
- -
+

{{ playlist_title }}

- 播放 - 添加到当前播放 - 收藏 - 编辑 - 原始链接 - 导入合并 +
+
+
{{_PLAY_ALL}} +
+
+
+
+
{{_ADD_TO_PLAYLIST}}
+
+
+
{{_EDIT}}
+
+
+
{{_ORIGIN_LINK}}
+
+
+
{{_IMPORT}}
+
-
-
-
- + +
+
+ +
+ + + +
- -
+
+
+
+
+
- +
+
+
+ + + \ No newline at end of file diff --git a/app/listen1_chrome_extension/manifest.json b/app/listen1_chrome_extension/manifest.json index c9a87b3..9ec517f 100644 --- a/app/listen1_chrome_extension/manifest.json +++ b/app/listen1_chrome_extension/manifest.json @@ -1,6 +1,6 @@ { "background": { - "scripts": ["js/vendor/jquery-2.2.3.min.js", "js/github_api.js","js/background.js" ] + "scripts": ["js/vendor/jquery-3.3.1.min.js", "js/github_api.js","js/background.js" ] }, "browser_action": { "default_icon": "images/logo.png", @@ -14,8 +14,8 @@ }, "manifest_version": 2, "name": "Listen 1", - "permissions": [ "notifications", "unlimitedStorage", "downloads", "storage", "contextMenus", "tabs", "cookies", "*://music.163.com/*", "*://*.xiami.com/*", "*://*.qq.com/*", "*://*.kugou.com/", "*://*.kuwo.cn/", "*://api.github.com/*", "*://github.com/*", "webRequest", "webRequestBlocking"], - "version": "1.9.0", + "permissions": [ "notifications", "unlimitedStorage", "downloads", "storage", "contextMenus", "tabs", "cookies", "*://music.163.com/*", "*://*.xiami.com/*", "*://*.qq.com/*", "*://*.kugou.com/", "*://*.kuwo.cn/", "*://*.bilibili.com/*", "*://api.github.com/*", "*://github.com/*", "*://gist.githubusercontent.com/*", "webRequest", "webRequestBlocking"], + "version": "2.1.0", "web_accessible_resources": [ "images/*" ], "content_scripts": [{ "matches": ["https://listen1.github.io/listen1/*"], diff --git a/app/listen1_chrome_extension/manifest_firefox.json b/app/listen1_chrome_extension/manifest_firefox.json index 4a747a7..7b7887e 100644 --- a/app/listen1_chrome_extension/manifest_firefox.json +++ b/app/listen1_chrome_extension/manifest_firefox.json @@ -6,7 +6,7 @@ } }, "background": { - "scripts": ["js/vendor/jquery-2.2.3.min.js", "js/github_api.js","js/background.js" ] + "scripts": ["js/vendor/jquery-3.3.1.min.js", "js/github_api.js","js/background.js" ] }, "browser_action": { "default_icon": "images/logo.png", @@ -20,12 +20,12 @@ }, "manifest_version": 2, "name": "Listen 1", - "permissions": [ "notifications", "unlimitedStorage", "downloads", "storage", "contextMenus", "tabs", "*://music.163.com/*", "*://*.xiami.com/*", "*://*.qq.com/*", "*://*.kugou.com/", "*://*.kuwo.cn/", "*://api.github.com/*", "*://github.com/*", "webRequest", "webRequestBlocking"], - "version": "1.9.0", + "permissions": [ "notifications", "unlimitedStorage", "downloads", "storage", "contextMenus", "tabs", "cookies", "*://music.163.com/*", "*://*.xiami.com/*", "*://*.qq.com/*", "*://*.kugou.com/", "*://*.kuwo.cn/", "*://*.bilibili.com/*", "*://api.github.com/*", "*://github.com/*", "*://gist.githubusercontent.com/*", "webRequest", "webRequestBlocking"], + "version": "2.1.0", "web_accessible_resources": [ "images/*" ], "content_scripts": [{ "matches": ["https://listen1.github.io/listen1/*"], "js": ["js/oauth_callback.js"] }] - } } + diff --git a/app/main.js b/app/main.js index 1e932c9..b527203 100644 --- a/app/main.js +++ b/app/main.js @@ -1,22 +1,25 @@ const electron = require('electron') - // const electronAcrylic = require('windows10-fluently-vibrancy'); // Module to control application life. -const app = electron.app - /*获取electron窗体的菜单栏*/ -const Menu = electron.Menu - /*隐藏electron创听的菜单栏*/ -Menu.setApplicationMenu(null) - // Module to create native browser window. +const { app, globalShortcut } = require('electron') + +const { ipcMain } = require('electron') + +// Module to create native browser window. const BrowserWindow = electron.BrowserWindow var path = require('path') var iconPath = path.join(__dirname, '/listen1_chrome_extension/images/logo.png'); - // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. let mainWindow let willQuitApp = false; +var windowState = { maximized: false } + +const globalShortcutMapping = { + 'CmdOrCtrl+Alt+Left': 'left', + 'CmdOrCtrl+Alt+Right': 'right', +}; function initialTray(mainWindow) { const { app, Menu, Tray } = require('electron'); @@ -26,46 +29,58 @@ function initialTray(mainWindow) { var trayIconPath = path.join(__dirname, '/resources/logo_16.png'); appTray = new Tray(trayIconPath); - function toggleVisiable() { - var isVisible = mainWindow.isVisible(); - if (isVisible) { - mainWindow.hide(); - - // mainWindow.minimize(); - } else { - mainWindow.show(); - } + function toggleVisiable() { + var isVisible = mainWindow.isVisible(); + if (isVisible) { + mainWindow.hide(); + } else { + mainWindow.show(); } - const contextMenu = Menu.buildFromTemplate([{ - label: 'Show/Hide Window', - click() { - toggleVisiable(); - } - }, - { - label: 'Quit', - click() { - app.quit(); - } - }, - ]); - //appTray.setToolTip('This is my application.'); - appTray.setContextMenu(contextMenu); - appTray.on('click', function handleClicked() { - toggleVisiable(); + } + const contextMenu = Menu.buildFromTemplate([ + {label: '显示/隐藏窗口', click(){ + toggleVisiable(); + }}, + {label: '退出', click() { + app.quit(); + }}, + ]); + //appTray.setToolTip('This is my application.'); + appTray.setContextMenu(contextMenu); + appTray.on('click', function handleClicked () { + toggleVisiable(); + }); +} + +function setKeyMapping(key, message) { + const ret = globalShortcut.register(key, () => { + mainWindow.webContents.send('globalShortcut', message); }); } +function enableGlobalShortcuts() { + // initial global shortcuts + for (let key in globalShortcutMapping) { + setKeyMapping(key, globalShortcutMapping[key]); + } +} + +function disableGlobalShortcuts() { + for (let key in globalShortcutMapping) { + globalShortcut.unregister(key); + } + + globalShortcut.unregisterAll() +} function createWindow() { const session = require('electron').session; - const filter = { - urls: ["*://music.163.com/*", "*://*.xiami.com/*", "*://*.qq.com/*", - "https://listen1.github.io/listen1/callback.html?code=*" - ] - }; + const filter = { + urls: ["*://music.163.com/*", "*://*.xiami.com/*", "*://*.qq.com/*", "*://*.kugou.com/*", "*://*.bilibili.com/*", "*://*.githubusercontent.com/*", + "https://listen1.github.io/listen1/callback.html?code=*"] + }; session.defaultSession.webRequest.onBeforeSendHeaders(filter, function(details, callback) { if (details.url.startsWith("https://listen1.github.io/listen1/callback.html?code=")) { @@ -78,26 +93,30 @@ function createWindow() { callback({ cancel: false, requestHeaders: details.requestHeaders }); }); + // var transparent = false; + // if (process.platform == 'darwin') { + // transparent = true; + // } // Create the browser window. mainWindow = new BrowserWindow({ - width: 940, - height: 600, - 'webPreferences': { 'nodeIntegration': true }, - transparent: true, + width: 1000, + height: 670, + webPreferences: { 'nodeIntegration': true }, icon: iconPath, - frame: false + titleBarStyle: 'hiddenInset', + transparent: true, + vibrancy: 'light', + frame: false, + hasShadow: true }); - // 开启开发者模式 + // 打开开发者工具 // mainWindow.webContents.openDevTools(); - mainWindow.on('minimize', function(event) { - event.preventDefault(); - mainWindow.hide(); - }); const electronVibrancy = require('windows10-fluently-vibrancy'); electronVibrancy.enableVibrancy(mainWindow, 2); // mainWindow.webContents.openDevTools(); + mainWindow.on('close', (e) => { if (willQuitApp) { /* the user tried to quit the app */ @@ -118,7 +137,7 @@ function createWindow() { mainWindow.loadURL(`file://${__dirname}/listen1_chrome_extension/listen1.html`) // Open the DevTools. - //mainWindow.webContents.openDevTools() + // mainWindow.webContents.openDevTools() // Emitted when the window is closed. mainWindow.on('closed', function() { @@ -149,48 +168,117 @@ function createWindow() { ] }]; - electron.Menu.setApplicationMenu(null); - // electron.Menu.setApplicationMenu(electron.Menu.buildFromTemplate(template)); + mainWindow.setMenu(null); + + //electron.Menu.setApplicationMenu(electron.Menu.buildFromTemplate(template)); initialTray(mainWindow); } - function hack_referer_header(details) { - var refererValue = ''; + let replace_referer = true; + let replace_origin = true; + let add_referer = true; + let add_origin = true; + var referer_value = ''; + if (details.url.indexOf("://music.163.com/") != -1) { - refererValue = "http://music.163.com/"; + referer_value = "http://music.163.com/"; + } + if (details.url.indexOf("://gist.githubusercontent.com/") != -1) { + referer_value = "https://gist.githubusercontent.com/"; } - if (details.url.indexOf(".xiami.com/") != -1) { - refererValue = "http://m.xiami.com/"; + if (details.url.indexOf("api.xiami.com/") != -1 || details.url.indexOf('.xiami.com/song/playlist/id/') != -1) { + referer_value = "https://www.xiami.com/"; } if ((details.url.indexOf("y.qq.com/") != -1) || (details.url.indexOf("qqmusic.qq.com/") != -1) || (details.url.indexOf("music.qq.com/") != -1) || (details.url.indexOf("imgcache.qq.com/") != -1)) { - refererValue = "http://y.qq.com/"; + referer_value = "http://y.qq.com/"; + } + if (details.url.indexOf(".kugou.com/") != -1) { + referer_value = "http://www.kugou.com/"; + } + if (details.url.indexOf(".kuwo.cn/") != -1) { + referer_value = "http://www.kuwo.cn/"; + } + if (details.url.indexOf(".bilibili.com/") != -1) { + referer_value = "http://www.bilibili.com/"; + replace_origin = false; + add_origin = false; } var isRefererSet = false; - var headers = details.requestHeaders; + var isOriginSet = false; + var headers = details.requestHeaders, + blockingResponse = {}; + + for (var i = 0, l = headers.length; i < l; ++i) { - if ((headers[i].name == 'Referer') && (refererValue != '')) { - headers[i].value = refererValue; + if (replace_referer && (headers[i].name == 'Referer') && (referer_value != '')) { + headers[i].value = referer_value; isRefererSet = true; - break; + } + if (replace_origin && (headers[i].name == 'Origin') && (referer_value != '')) { + headers[i].value = referer_value; + isOriginSet = true; } } - if ((!isRefererSet) && (refererValue != '')) { - headers["Origin"] = refererValue; - headers["Referer"] = refererValue; + if (add_referer && (!isRefererSet) && (referer_value != '')) { + headers["Referer"] = referer_value; } + + if (add_origin && (!isOriginSet) && (referer_value != '')) { + headers["Origin"] = referer_value; + } + details.requestHeaders = headers; }; + +ipcMain.on('control', (event, arg) => { + // console.log(arg); + if (arg == 'enable_global_shortcut') { + enableGlobalShortcuts(); + } else if (arg == 'disable_global_shortcut') { + disableGlobalShortcuts(); + } else if (arg == 'window_min') { + mainWindow.minimize(); + } else if (arg == 'window_max') { + if (windowState.maximized == true) { + windowState.maximized = false; + mainWindow.unmaximize(); + } else { + windowState.maximized = true; + mainWindow.maximize(); + } + } else if (arg == 'window_close') { + mainWindow.close(); + } + // event.sender.send('asynchronous-reply', 'pong') +}) + + + +var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) { + console.log(commandLine, workingDirectory); + // Someone tried to run a second instance, we should focus our window. + if (mainWindow) { + if (mainWindow.isMinimized()) mainWindow.restore(); + mainWindow.focus(); + } +}); +// console.log(shouldQuit); +if (shouldQuit) { + app.quit(); + return; +} + // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. @@ -198,31 +286,21 @@ app.on('ready', createWindow) // Quit when all windows are closed. app.on('window-all-closed', function() { - // On OS X it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== 'darwin') { - app.quit() - } - }) - /* 'activate' is emitted when the user clicks the Dock icon (OS X) */ + // On OS X it is common for applications and their menu bar + // to stay active until the user quits explicitly with Cmd + Q + if (process.platform !== 'darwin') { + app.quit() + } +}) + + +/* 'activate' is emitted when the user clicks the Dock icon (OS X) */ app.on('activate', () => mainWindow.show()); /* 'before-quit' is emitted when Electron receives * the signal to exit and wants to start closing windows */ app.on('before-quit', () => willQuitApp = true); -// function toggleVisiable() { -// var isVisible = mainWindow.isVisible(); -// if (isVisible) { -// mainWindow.hide(); -// } else { -// mainWindow.show(); -// } -// } - -// toggleVisiable(); -// // remote.mainWindow.minimize(); -// // initialTray(mainWindow).toggleVisiable(); -// // app.quit(); -// // remote.getCurrentWindow().close(); -// } \ No newline at end of file +app.on('will-quit', () => { + disableGlobalShortcuts(); +}) \ No newline at end of file diff --git a/app/package.json b/app/package.json index affd0ea..5a7af78 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "Listen1", - "version": "1.9.0", + "version": "2.1.0", "description": "One for all free music in China", "main": "main.js", "scripts": { @@ -11,9 +11,6 @@ "type": "git", "url": "git+https://github.com/listen1/listen1_desktop.git" }, - "dependencies": { - "windows10-fluently-vibrancy": "^0.9.2" - }, "keywords": [ "Electron", "Listen 1", @@ -24,5 +21,8 @@ "bugs": { "url": "https://github.com/listen1/listen1_desktop/issues" }, - "homepage": "https://github.com/listen1/listen1_desktop#readme" + "homepage": "https://github.com/listen1/listen1_desktop#readme", + "dependencies": { + "windows10-fluently-vibrancy": "^0.9.2" + } } diff --git a/package.json b/package.json index 3266b26..a792a1f 100644 --- a/package.json +++ b/package.json @@ -1,86 +1,86 @@ { - "name": "Listen1", - "version": "1.9.0", - "description": "One for all free music in China", - "main": "app/main.js", - "scripts": { - "postinstall": "install-app-deps", - "start": "electron . --inspect-brk=5858 --enable-logging", - "dev": "NODE_ENV='development' npm run start", - "dist:mac": "CSC_IDENTITY_AUTO_DISCOVERY=false DEBUG=electron-builder electron-builder --platform darwin", - "dist": "electron-builder .", - "dist:linux": "electron-builder --linux --ia32 --x64", - "dist:linux32": "electron-builder --linux --ia32", - "dist:linux64": "electron-builder --linux --x64", - "dist:win": "electron-builder --win --ia32 --x64", - "dist:win32": "electron-builder --win --ia32", - "dist:win64": "electron-builder --win --x64" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/listen1/listen1_desktop.git" - }, - "keywords": [ - "Electron", - "Listen 1" - ], - "author": "Listen 1 ", - "license": "MIT", - "bugs": { - "url": "https://github.com/listen1/listen1_desktop/issues" - }, - "homepage": "https://github.com/listen1/listen1_desktop#readme", - "build": { - "appId": "com.listen1.listen1", - "productName": "Listen1", - "asar": false, - "artifactName": "${name}_${version}_${os}${arch}.${ext}", - "dmg": { - "title": "Listen 1", - "icon": "build/disk.icns", - "background": "build/background.png", - "iconSize": 80, - "contents": [{ - "x": 192, - "y": 344 - }, - { - "x": 448, - "y": 344, - "type": "link", - "path": "/Applications" - } - ] + "name": "Listen1", + "version": "2.1.0", + "description": "One for all free music in China", + "main": "app/main.js", + "scripts": { + "postinstall": "install-app-deps", + "start": "electron ./app --enable-logging", + "dev": "NODE_ENV='development' npm run start", + "dist:mac": "CSC_IDENTITY_AUTO_DISCOVERY=false DEBUG=electron-builder electron-builder --platform darwin", + "dist": "electron-builder .", + "dist:linux": "electron-builder --linux --ia32 --x64", + "dist:linux32": "electron-builder --linux --ia32", + "dist:linux64": "electron-builder --linux --x64", + "dist:win": "electron-builder --win --ia32 --x64", + "dist:win32": "electron-builder --win --ia32", + "dist:win64": "electron-builder --win --x64" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/listen1/listen1_desktop.git" + }, + "keywords": [ + "Electron", + "Listen 1" + ], + "author": "Listen 1 ", + "license": "MIT", + "bugs": { + "url": "https://github.com/listen1/listen1_desktop/issues" + }, + "homepage": "https://github.com/listen1/listen1_desktop#readme", + "build": { + "appId": "com.listen1.listen1", + "productName": "Listen1", + "asar": true, + "artifactName": "${name}_${version}_${os}_${arch}.${ext}", + "dmg": { + "title": "Listen 1", + "icon": "build/disk.icns", + "background": "build/background.png", + "iconSize": 80, + "contents": [ + { + "x": 192, + "y": 344 }, - "linux": { - "target": [ - "tar.gz", - "appImage", - "deb" - ] - }, - "nsis": { - "runAfterFinish": false, - "deleteAppDataOnUninstall": true, - "allowToChangeInstallationDirectory": true, - "oneClick": false, - "installerLanguages": "zh_CN", - "language": 2052, - "perMachine": true, - "createDesktopShortcut": true - }, - "win": { - "target": "nsis", - "icon": "build/icon.ico" + { + "x": 448, + "y": 344, + "type": "link", + "path": "/Applications" } + ] + }, + "linux": { + "target": [ + "tar.gz", + "appImage", + "deb" + ] }, - "devDependencies": { - "electron": "^3.0.8", - "electron-builder": "^19.56.2", - "electron-rebuild": "^1.8.2" + "nsis": { + "runAfterFinish": false, + "deleteAppDataOnUninstall": true, + "allowToChangeInstallationDirectory": true, + "oneClick": false, + "installerLanguages": "zh_CN", + "language": 2052, + "perMachine": true, + "createDesktopShortcut": true }, - "dependencies": { - "electron-debug": "^1.5.0", - "windows10-fluently-vibrancy": "^0.9.2" + "win": { + "target": "nsis", + "icon": "build/icon.ico" } -} \ No newline at end of file + }, + "devDependencies": { + "electron": "^3.0.13", + "electron-builder": "^20.38.3" + }, + "dependencies": { + "electron-debug": "^1.5.0", + "windows10-fluently-vibrancy": "^0.9.2" + } +}