From 2d9f775d4f4d2281f333912678092abdd4e532dc Mon Sep 17 00:00:00 2001 From: listen1 Date: Sat, 30 Apr 2016 14:42:45 +0800 Subject: [PATCH] initial commit --- .gitignore | 1 + LICENSE | 20 + README.md | 34 + css/angular-ui-notification.css | 82 + css/bootstrap.min.css | 6 + css/cover.css | 163 + css/player.css | 848 ++ css/reset.css | 64 + images/favicon.ico | Bin 0 -> 4286 bytes images/loading.gif | Bin 0 -> 63626 bytes images/logo.png | Bin 0 -> 3452 bytes images/mycover.jpg | Bin 0 -> 5752 bytes images/placeholder.png | Bin 0 -> 4028 bytes images/playbar.png | Bin 0 -> 45399 bytes images/player_directplay.png | Bin 0 -> 1628 bytes images/player_large.png | Bin 0 -> 5353 bytes images/player_small.png | Bin 0 -> 5480 bytes images/progress_indicator.png | Bin 0 -> 1594 bytes images/statbar.png | Bin 0 -> 1380 bytes js/aes.js | 671 ++ js/app.js | 806 ++ js/background.js | 47 + js/bigint.js | 1507 ++++ js/loweb.js | 90 + js/lowebutil.js | 9 + js/netease.js | 310 + js/qq.js | 228 + js/vendor/angular-soundmanager2.js | 5293 ++++++++++++ js/vendor/angular-ui-notification.js | 183 + js/vendor/angular.min.js | 314 + js/vendor/jquery-1.12.2.js | 11022 +++++++++++++++++++++++++ js/xiami.js | 226 + listen1.html | 321 + manifest.json | 21 + 34 files changed, 22266 insertions(+) create mode 100644 .gitignore create mode 100755 LICENSE create mode 100644 README.md create mode 100644 css/angular-ui-notification.css create mode 100644 css/bootstrap.min.css create mode 100644 css/cover.css create mode 100644 css/player.css create mode 100755 css/reset.css create mode 100644 images/favicon.ico create mode 100644 images/loading.gif create mode 100755 images/logo.png create mode 100644 images/mycover.jpg create mode 100644 images/placeholder.png create mode 100644 images/playbar.png create mode 100644 images/player_directplay.png create mode 100644 images/player_large.png create mode 100644 images/player_small.png create mode 100644 images/progress_indicator.png create mode 100644 images/statbar.png create mode 100644 js/aes.js create mode 100644 js/app.js create mode 100644 js/background.js create mode 100644 js/bigint.js create mode 100644 js/loweb.js create mode 100644 js/lowebutil.js create mode 100644 js/netease.js create mode 100644 js/qq.js create mode 100644 js/vendor/angular-soundmanager2.js create mode 100644 js/vendor/angular-ui-notification.js create mode 100644 js/vendor/angular.min.js create mode 100644 js/vendor/jquery-1.12.2.js create mode 100644 js/xiami.js create mode 100644 listen1.html create mode 100644 manifest.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..c2312c1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2016 Listen 1 + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..465bcb6 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +Listen 1 (Chrome Extension) (五一先行版) +========== + +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE) + +缘起 +---- +当我发现找个想听的歌因为版权听不了,需要打开好几个网站开始搜索,来回切换让我抓狂的时候,我知道是时候该做点什么了。 + +妈妈再也不用担心我找不到我想听的歌了。这里包含了网易云音乐,虾米,QQ音乐的曲库,够全够大了吧。 + +搜歌,听歌,就用 `Listen1`。 + +[![imgur](http://i.imgur.com/yblr3KO.gif)]() + +还有精选歌单哦。 + +安装 +---- +不能直接用chrome打开安装,不能直接用chrome打开安装,不能直接用chrome打开安装。重要的话说三遍。 + +chrome右上角的设置按钮下找到更多工具,打开扩展程序 + +把crx文件拖到扩展程序页面里,完成! + + +TODO +---- +加入我的歌单功能(如迫不及待需要,可以安装Listen 1非插件版) + + +License +-------- +MIT diff --git a/css/angular-ui-notification.css b/css/angular-ui-notification.css new file mode 100644 index 0000000..5c523a1 --- /dev/null +++ b/css/angular-ui-notification.css @@ -0,0 +1,82 @@ +/** + * angular-ui-notification - Angular.js service providing simple notifications using Bootstrap 3 styles with css transitions for animating + * @author Alex_Crack + * @version v0.1.0 + * @link https://github.com/alexcrack/angular-ui-notification + * @license MIT + */ +.ui-notification +{ + position: fixed; + z-index: 9999; + + width: 300px; + + cursor: pointer; + -webkit-transition: all ease .5s; + -o-transition: all ease .5s; + transition: all ease .5s; + + color: #fff; + border-radius: 0; + background: #337ab7; + box-shadow: 5px 5px 10px rgba(0, 0, 0, .3); +} +.ui-notification.killed +{ + -webkit-transition: opacity ease 1s; + -o-transition: opacity ease 1s; + transition: opacity ease 1s; + + opacity: 0; +} +.ui-notification > h3 +{ + font-size: 14px; + font-weight: bold; + + display: block; + + margin: 10px 10px 0 10px; + padding: 0 0 5px 0; + + text-align: left; + + border-bottom: 1px solid rgba(255, 255, 255, .3); +} +.ui-notification a +{ + color: #fff; +} +.ui-notification a:hover +{ + text-decoration: underline; +} +.ui-notification > .message +{ + margin: 10px 10px 10px 10px; +} +.ui-notification.warning +{ + color: #fff; + background: #f0ad4e; +} +.ui-notification.error +{ + color: #fff; + background: #d9534f; +} +.ui-notification.success +{ + color: #fff; + background: #5cb85c; +} +.ui-notification.info +{ + color: #fff; + background: #5bc0de; +} +.ui-notification:hover +{ + opacity: .7; +} diff --git a/css/bootstrap.min.css b/css/bootstrap.min.css new file mode 100644 index 0000000..4cf729e --- /dev/null +++ b/css/bootstrap.min.css @@ -0,0 +1,6 @@ +/*! + * Bootstrap v3.3.6 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/css/cover.css b/css/cover.css new file mode 100644 index 0000000..d45cddc --- /dev/null +++ b/css/cover.css @@ -0,0 +1,163 @@ +/* + * Globals + */ + +/* Links */ +a, +a:focus, +a:hover { + color: #fff; +} + +/* Custom default button */ +.btn-default, +.btn-default:hover, +.btn-default:focus { + color: #333; + text-shadow: none; /* Prevent inheritence from `body` */ + background-color: #fff; + border: 1px solid #fff; +} + + +/* + * Base structure + */ + +html, +body { + height: 100%; + background-color: #333; +} +body { + color: #fff; +/* text-align: center;*/ + /*text-shadow: 0 1px 3px rgba(0,0,0,.5);*/ +} + +/* Extra markup and styles for table-esque vertical and horizontal centering */ +.site-wrapper { + display: table; + width: 100%; + height: 100%; /* For at least Firefox */ + min-height: 100%; +/* -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; +} +.cover-container { + margin-right: auto; + margin-left: auto; +} + +/* Padding for spacing */ +.inner { + padding: 30px; +} + + +/* + * Header + */ +.masthead-brand { + margin-top: 10px; + margin-bottom: 10px; +} + +.masthead-nav > li { + display: inline-block; +} +.masthead-nav > li + li { + margin-left: 20px; +} +.masthead-nav > li > a { + padding-right: 0; + padding-left: 0; + font-size: 16px; + font-weight: bold; + color: #fff; /* IE8 proofing */ + color: rgba(255,255,255,.75); + border-bottom: 2px solid transparent; +} +.masthead-nav > li > a:hover, +.masthead-nav > li > a:focus { + background-color: transparent; + border-bottom-color: #a9a9a9; + border-bottom-color: rgba(255,255,255,.25); +} +.masthead-nav > .active > a, +.masthead-nav > .active > a:hover, +.masthead-nav > .active > a:focus { + color: #fff; + border-bottom-color: #fff; +} + +@media (min-width: 768px) { + .masthead-brand { + float: left; + } + .masthead-nav { + float: right; + } +} + + +/* + * Cover + */ + +.cover { + padding: 0 20px; +} +.cover .btn-lg { + padding: 10px 20px; + font-weight: bold; +} + + +/* + * Footer + */ + +.mastfoot { + color: #999; /* IE8 proofing */ + color: rgba(255,255,255,.5); +} + + +/* + * Affix and center + */ + +@media (min-width: 768px) { + /* Pull out the header and footer */ + .masthead { + position: fixed; + top: 0; + } + .mastfoot { + position: fixed; + bottom: 0; + } + /* Start the vertical centering */ + .site-wrapper-inner { + vertical-align: middle; + } + /* Handle the widths */ + .masthead, + .mastfoot, + .cover-container { + width: 100%; /* Must be percentage or pixels for horizontal alignment */ + } +} + +@media (min-width: 992px) { + .masthead, + .mastfoot, + .cover-container { + width: 880px; + } +} \ No newline at end of file diff --git a/css/player.css b/css/player.css new file mode 100644 index 0000000..0ed2371 --- /dev/null +++ b/css/player.css @@ -0,0 +1,848 @@ +a { + cursor: pointer; +} + +.shadow { + position: fixed; + background: rgba(30,30,30,0.9); + _position: absolute; + z-index: 9999; + top: 0; + bottom: 0; + left: 0; + right: 0; + width: 100%; + height: 100%; + background-image: url(data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==); +} + +.dialog { + position: absolute; + top: 120px; + width: 480px; + height: 420px; + z-index:10000; + overflow: hidden; + border-radius: 4px 4px 4px 4px; + padding: 20px; + background-color: #333; + +} + +.dialog-header { + width: 100%; + height: 30px; + font-family: Arial, Helvetica, sans-serif; + font-size: 15px; + font-weight: bold; + text-align: left; + border-bottom: 1px solid; + margin-bottom: 20px; +} + +.dialog-header .dialog-close { + float: right; + font-size: 33px; + cursor: pointer; + margin-top: -15px; +} + +.dialog-body { + width: 100%; + height: 320px; + overflow-y: auto; + background-color: #333; +} + +/*.masthead { + z-index: 999; +}*/ + +.masthead, .mastfoot { + margin: 0 auto; + left: 0; + right: 0; + z-index: 999; + background-color: #222222; +} + +.masthead { + background-color: #333; + height: 90px; +} + +.masthead .logo { + float: left; + height: 50px; + width: 50px; + margin-right: 20px; +} + +.cover-container { + position: relative; +} + +.site-wrapper { + width:100%; + overflow:hidden; + position: absolute; + padding-left: 17px; +} + +.site-wrapper-innerd { + overflow-y: scroll; + margin-top: 90px; + /* uncomment the line below will hide the scroll bar */ + /*padding-right: 17px;*/ + box-sizing:content-box; + width:100%; + background-color: #333; +} + +.searchbox { +/* margin-top: 100px;*/ +} + +.searchbox .nav{ + margin-top: 12px; +} + + +.searchitem { + height: 92px; +} + +.searchitem img { + float: left; + height:90px; + width:90px; +} + +.searchitem div { + float: left; + margin-left: 48px; + margin-top: 38px; + width: 400px; +} + +.playlist-covers li { + float: left; + display: inline-block; + width: 140px; + height: 188px; + margin-right: 22px; +} + +.playlist-covers .desc { + text-align: left; +} + +.playlist-covers .u-cover { + position: relative; + display: block; + width: 140px; + height: 140px; +} + +.playlist-covers .u-cover .bottom { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 27px; + color: #ccc; +} + +.u-cover .mask { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.u-cover img { + display: block; + width: 100%; + height: 100%; +} + +.u-cover .icon-play { + position: absolute; + right: 10px; + bottom: 5px; + width: 16px; + height: 17px; + background: url(../images/player_directplay.png); +} + +.playlist-covers .u-cover .bottom .nb { + float: left; + margin: 7px 0 0 0; +} + +.m-playbar { + position: absolute; + zoom: 1; + top: -90px; + left: 0; + width: 100%; + height: 90px; + margin: 0 auto; + 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 { + float: left; +} + +.m-pbar .btn i { + visibility: hidden; + position: absolute; + left: 5px; + top: 5px; + width: 12px; + height: 12px; + background: url(../images/loading.gif); +} + +.m-pbar .barbg, .m-pbar .cur, .m-pbar .left { + background: url(../images/statbar.png) no-repeat 0 9999px; + _background-image: url(../images/statbar.png); +} + +.m-playbar .btns a { + background: url(../images/player_large.png) no-repeat 0 9999px; + _background-image: url(../images/player_large.png); + cursor: pointer; +} + +.m-playbar .btns a { + display: block; + float: left; + width: 36px; + height: 36px; + margin-right: 8px; + margin-top: 0px; + text-indent: -9999px; +} + +.m-playbar .btns .previous{ + background-position: -72px 0px; +} + +.m-playbar .btns .previous:hover{ + background-position:-72px -36px; +} + +.m-playbar .btns .play{ + width: 36px; + height: 36px; + margin-top:0; + background-position: 0px 0px; +} + +.m-playbar .btns .play:hover{ + background-position: 0px -36px; +} + +.m-playbar .btns .pas{ + background-position: -108px 0px; +} + +.m-playbar .btns .pas:hover{ + background-position: -108px -36px; +} + +.m-playbar .btns .next{ + /* pause icon distance adjust from 36 to 38 */ + background-position: -38px 0px; +} + +.m-playbar .btns .next:hover{ + background-position: -38px -36px; +} + +.m-playbar .head { + position: relative; + margin: 10px 15px 0 0; +} + +.m-playbar .head, .m-playbar .head img { + width: 70px; + height: 70px; +} + +.m-playbar .head .mask { + position: absolute; + top: 0px; + left: 0px; + display: block; + width: 70px; + height: 70px; +} + +.m-playbar .maininfo { + float: none; + margin-left: 245px; + margin-right: 120px; +} + +.m-playbar .words .notextdeco{ + text-decoration: none; +} + +.m-playbar .words { + margin-top: 14px; + height: 28px; + overflow: hidden; + color: #e8e8e8; + text-shadow: 0 1px 0 #171717; + line-height: 28px; +} + +.m-playbar .words .name { + max-width: 300px; +} + +.m-playbar .words .by { + max-width: 220px; + margin-left: 15px; + color: #9b9b9b; +} + +.m-playbar .words .by a { + color: #9b9b9b; +} + +.m-playbar .words .src { + cursor: pointer; + float: left; + width: 25px; + height: 25px; + margin: 2px 0 0 13px; + background: url(../images/player_small.png) no-repeat 0 9999px; + background-position: -100px 0px; +} + +.m-playbar .words .src:hover { + background-position: -100px -25px; +} + +.m-playbar .words .fc1 { + color: #e8e8e8; + margin-left: 3px; +} + +.overflowhide { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.floatleft { + float: left; +} + +.m-pbar { + position: relative; + margin-top: 14px; + width: 80%; +} + +.m-pbar .barbg, .m-pbar .cur, .m-pbar .rdy { + height: 7px; +} + +.m-pbar .barbg { + background-position: right 0; +} + + +.m-pbar .cur { + position: absolute; + top: 0; + left: 0; + width: 1%; + background-position: left -9px; +} + +.m-pbar .btn { + position: absolute; + top: -8px; + right: -13px; + width: 22px; + height: 24px; + margin-left: -11px; + background: url(../images/progress_indicator.png) no-repeat; +} + +.m-playbar .time { + position: absolute; + right: -122px; + top: -6px; +} + +.m-playbar .time { + float: right; + margin-right: 20px; + color: #797979; + text-shadow: 0 1px 0 #121212; +} + +.m-playbar .time em { + color: #a1a1a1; +} + +em, i { + font-style: normal; + text-align: left; + font-size: inherit; +} + +.m-playbar a { + background: url(../images/player_small.png) no-repeat 0 9999px; +} + +.m-playbar .ctrl { + position: absolute; + right: 0px; + bottom: 17px; + z-index: 10; + width: 110px; + padding-left: 13px; + float: none; +} + + + +.m-playbar .icn-add { + background-position: -25px 0px; +} + +.m-playbar .icn-add:hover { + background-position: -25px -25px; +} + +.m-playbar .icn-list { + background-position: -125px 0px; +} + +.m-playbar .icn-list:hover { + background-position: -125px -25px; +} + +.m-playbar .icn-loop { + background-position: -50px 0px; +} + +.m-playbar .icn-loop:hover { + background-position: -50px -25px; +} + + +.m-playbar .icn-shuffle { + background-position: -150px 0px; +} + +.m-playbar .icn-shuffle:hover { + background-position: -150px -25px; +} + + +.m-playbar .icn { + float: left; + width: 25px; + height: 25px; + margin: 11px 2px 0 0; + text-indent: -9999px; +} + +.m-playbar .menu { + position: absolute; + bottom: 90px; + _bottom: 90px; + right: 0px; + _right: 0px; + width: 60%; + height: 301px; + background-color: #121212; +} + +.m-playbar .menu ul { + padding-left: 0px; + height: 270px; + overflow: auto; +} + +.m-playbar .menu li { + float: left; + width: 100%; + display: block; +} + +.m-playbar .menu .playing { + background-color: #555555; +} + +.m-playbar .menu li:hover, .m-playbar .menu li:focus { + background-color: #999999; +} + +.m-playbar .menu .icn-remove { + height: 25px; + width: 25px; + background-position: -75px -25px; + display: inline-block; +} + +.m-playbar .menu .icn-remove:hover { + background-position: -75px -25px; +} + +li { + list-style: none; +} + +.menu-header { + height: 28px; + background-color: #121212; + padding-top: 4px; + text-align: center; +} + +.menu .remove-all { + float:right; + margin-right: 10px; +} + +.menu .title { + width: 300px; + float: left; + height: 28px; + padding-top: 3px; + text-align: left; + padding-left: 20px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + cursor: pointer; +} + +.menu .singer { + width: 180px; + float: right; + height: 28px; + padding-top: 3px; + text-align: left; + padding-left: 20px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + cursor: pointer; +} + +.dbimport { + /*margin-top: 100px;*/ +} + +.form-signin { + width: 300px; + margin-left: auto; + margin-right: auto; + text-align: center; +} + +.form-signin .form-control, .form-signin .valid-img, .form-signin .btn { + margin-top: 10px; +} + +.form-signin .valid-img { + height: 40px; + width: 220px; +} + +.form-signin .security-notice { + margin-top: 10px; +} + +.playlist-detail { + position: absolute; + text-align: left; + background-color: #333; + width: 100%; +} + +.playlist-detail .detail-head { + width: 200px; + position: fixed; + margin-bottom: 20px; +} + +.playlist-detail .detail-head-cover { + height: 180px; +/* width: 225px;*/ + float: left; + margin: 10px; +} + +.playlist-detail .detail-head-cover img { + max-width:100%; + max-height:100%; +} + +.playlist-detail .detail-head-title { + float: left; + width: 100%; + text-align: center; +} + +.playlist-detail .detail-head-title .play { + display: inline-block; + text-indent: -9999px; + width: 36px; + height: 36px; + margin-right: 8px; + margin-top: 0; + background-position-x: 0; + background: url(../images/player_large.png) no-repeat 0 9999px; + background-position: 0px 0px; +} + +.playlist-detail .detail-head-title .play:hover { + background: url(../images/player_large.png) no-repeat 0 9999px; + background-position: 0px -36px; +} + +.playlist-detail .detail-head-title .delete { + display: inline-block; + text-indent: -9999px; + width: 36px; + height: 36px; + margin-right: 8px; + margin-top: 0; + background: url(../images/player_large.png) no-repeat 0 9999px; + background-position: -180px 0px; +} + +.playlist-detail .detail-head-title .delete:hover { + background: url(../images/player_large.png) no-repeat 0 9999px; + background-position: -180px -36px; +} + +.playlist-detail .detail-head-title .clone { + display: inline-block; + text-indent: -9999px; + width: 36px; + height: 36px; + margin-right: 8px; + margin-top: 0; + background: url(../images/player_large.png) no-repeat 0 9999px; + background-position: -144px 0px; +} + +.playlist-detail .detail-head-title .clone:hover { + background: url(../images/player_large.png) no-repeat 0 9999px; + background-position: -144px -36px; +} + +.playlist-detail .detail-head-title .ply:hover { + background-position: -40px -204px; +} + +.playlist-detail .detail-head-title h2{ + font-size: 17px; + margin-bottom: 35px; +} + +.playlist-detail .detail-songlist { + margin-left: 220px; + margin-top: 6px; + margin-right: 14px; +} + +.detail-songlist { + padding-left: 0px; + text-align: left; +} + +.detail-songlist li { + float: left; + width: 100%; + display: block; + padding: 8px; +} + +.detail-songlist .col2 { + float: left; + width: 28%; + margin-left: 2%; + font-size: 15px; +} + +.detail-songlist .col1 { + float: left; + width: 19%; + margin-left: 2%; +} + +.detail-songlist .col-add { + float: left; + width: 75px; + margin-left: 2%; +} + +.detail-songlist .detail-tools { + float: right; + height: 35px; + position: relative; + width: 118px; +} + +.detail-songlist .detail-tools a { + background: url(../images/player_small.png) no-repeat 0 9999px; + height: 25px; + width: 25px; + cursor: pointer; +} + +.detail-songlist .detail-tools .detail-add-button{ + background-position: 0px 0px; +} + +.detail-songlist .detail-tools .detail-fav-button{ + background-position: -25px 0px; +} + +.detail-songlist .detail-tools .detail-delete-button{ + background-position: -75px 0px; +} + +.detail-songlist .detail-tools .source-button{ + background-position: -100px 0px; +} + +.detail-songlist .detail-tools .detail-add-button:hover{ + background-position: 0px -25px; +} + +.detail-songlist .detail-tools .detail-fav-button:hover{ + background-position: -25px -25px; +} + +.detail-songlist .detail-tools .detail-delete-button:hover{ + background-position: -75px -25px; +} + +.detail-songlist .detail-tools .source-button:hover{ + background-position: -100px -25px; +} + +.detail-songlist .detail-tools a { + text-decoration: none; + display: inline-block; +} + +.detail-songlist .detail-artist a{ + color: #777777; +} + +.detail-songlist .odd { + background-color: #333; +} + +.detail-songlist .even, .detail-songlist .detail-add{ + background-color: #2d2d2d; +} + +.dialog .detail-songlist li:hover { + background-color: #999999; + cursor: pointer; +} + +/*.playlist-detail .detail-songlist li:hover { + background-color: #999999; +}*/ + +.playlist-detail .btn{ + width: 88px; + margin-top: 0; + float: left; +} + +.playlist-detail .detail-close { + position: absolute; + right: -32px; + top: 0px; +} + +.playlist-detail .detail-close span { + font-size: 34px; + cursor: pointer; + color: #aaaaaa; +} + +.playlist-detail .detail-close span:hover { + color: #ffffff; +} + +.dialog-playlist { + padding-left: 0px; + text-align: left; +} + +.dialog-playlist li { + cursor: pointer; + height: 112px; + padding: 6px; +} + +.dialog-playlist li:hover { + background-color: #555555; +} + +.dialog-playlist li img { + float: left; + height: 100px; + width: 100px; +} + +.dialog-playlist li h2{ + margin-left: 125px; + font-size: 17px; +} + +.dialog-newplaylist input{ + margin-bottom: 22px; +} + +.dialog-newplaylist .confirm-button { + margin-right: 64px; +} + +.source-list { + position: absolute; + right: -32px; + top: 0px; +} + +.source-list button{ + background-color: #333333; + color: #fff; +} + +.settings-title { + font-size: 20px; + padding: 20px; + border-bottom: 2px solid #aaaaaa; +} + +.settings-content { + padding: 20px; +} \ No newline at end of file diff --git a/css/reset.css b/css/reset.css new file mode 100755 index 0000000..a194f6b --- /dev/null +++ b/css/reset.css @@ -0,0 +1,64 @@ +html, body, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, font, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend { + margin: 0; + padding: 0; + border: 0; + outline: 0; + font-weight: normal; + font-style: normal; + font-size: 100%; + vertical-align: baseline; +} + +: focus { + outline: 0; +} + +body { + line-height: 1.2; + color: black; + background: white; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: 100%; + font-weight: normal; +} + +ol, ul { + list-style: none; +} + +/* tables still need 'cellspacing="0"' in the markup */ +table { + border-collapse: separate; + border-spacing: 0; +} + +caption, th, td { + text-align: left; + font-weight: normal; +} + +blockquote:before, blockquote:after, +q:before, q:after { + content: ""; +} + +blockquote, q { + quotes: "" ""; +} + +img { + border: none; +} diff --git a/images/favicon.ico b/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..0995a87051e9a592b5373d24590a9ac45bda9955 GIT binary patch literal 4286 zcmeHLK?;B{42x$k;=!}*B7eydG-Zmp*m zw;cL?i;P-#ppl!Py53ow;t0yE%rzM>Gd+NpOvZ4IQqQ*0lu1VNeE!| literal 0 HcmV?d00001 diff --git a/images/loading.gif b/images/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..6a2a3a931d634717d69c4f0a828bc9f5c592e0cd GIT binary patch literal 63626 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%0DoW@ImWzVZSFP_-ja&w$rxveBDLb3UmcU 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 literal 0 HcmV?d00001 diff --git a/images/logo.png b/images/logo.png new file mode 100755 index 0000000000000000000000000000000000000000..11fd9ace90869646b3ac58869bdcfa9386f1b23c GIT binary patch literal 3452 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 literal 0 HcmV?d00001 diff --git a/images/mycover.jpg b/images/mycover.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5a36abeb63c81ca9066ee560bf405553a2514733 GIT binary patch literal 5752 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 Iz~#z60kC^4ivR!s literal 0 HcmV?d00001 diff --git a/images/playbar.png b/images/playbar.png new file mode 100644 index 0000000000000000000000000000000000000000..2bbe5170a530c253a3d2c1611b77e93649e2b10c GIT binary patch literal 45399 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 literal 0 HcmV?d00001 diff --git a/images/player_directplay.png b/images/player_directplay.png new file mode 100644 index 0000000000000000000000000000000000000000..b55a10b711458d2db93d4109b08636f6b95be1a8 GIT binary patch literal 1628 zcmeAS@N?(olHy`uVBq!ia0vp^0zfRt!3HF+tk*dLq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1FfeCihD4M^`1)8S=jZArg4F0$^BXQ!4Z zB&DWj=GiK}-@RW+Av48RDcsc8z_-9TH6zobswg$M$}c3jDm&RSMakYy!KT6rXh3di zNuokUZcbjYRfVk**jy_h8zii+qySb@l5ML5aa4qFfP!;=QL2Kep0RGSfuW&-nVFuU ziK&^Hp^k!)fuWJU0T7w#8k$&{npqi{D?ot~(6*wKG^-#NH>h1eo~=?wNlAf~zJ7Um zxn8-kUVc%!zM-Y1CCCgTBVC{h-Qvo;lEez#ykcdT2`;I{$wiq3C7Jno3Lp~`lk!VT zY?Xj6g?J&iz}FXUa9%MqpnyT9Uy)d#Z>VRWpPLKv7g%+1Nl+@n8CX>phg24%>IbD3 z=a&{G1LGr28KxN+cK9s=HGQCC z^g+o3DY?LefN2oKgeQI=2cCUW^MHA#2$(rk=I@%#z`)ey>EaktajPUGJ|iemM#adVA13o~`N7B!$JUU^$qUbOSh z@(7)6)6S;7PT3NnvzV{_@syi6W}9@ZdG9a&u$Sqwew!CVrW{-R?z?%c%?GESOeyj_ z6DBU)!}Pdpcde2DhtJBZS-mHAI>r|WU0kMFtRYgx_eq)M?xe3ztq*3HOcUWcdj96k zo6!pK?RoQZ&1RbmHn4W~AAj8Z#JnNTfa|7E=aI)w3l9jl@6b73c;)TFpp{z`PTO=w zT~~b1W7b=9V*7oEg2<^}r5$`LLtag-nRjAQ(~fS3>?WVwqvm<%u3?ppT;<)} z+-L8e|NJNM<(u!nw|l-z*x01-XF>DXG;3}3e+Q!?BY!?9v6BB)v+w()xaF67C+BR9 zV%olO<3=kZqoR$MUsg=*7apZ??}>i|^U%9@D1hsUj3v7Ud`I7#lwE#qm0aR2IUR@EN`DDJnr1HbLY=qiz9FS7hcTJ z*?ITf?+WHUKkWW6yuGbd5qP{Y6QAp_1F6|x86#W z63v?vpf`Q>#f&Wz{FYCD_}wo{>vO-=%ZGEAk2NGpnJaYsZ+Ucp`Stq!Ogs$i>Ly>z SmelF{r5}E+t&3FF* literal 0 HcmV?d00001 diff --git a/images/player_large.png b/images/player_large.png new file mode 100644 index 0000000000000000000000000000000000000000..f68dd0951c36792edcb892e7c8795e9535ac5b4d GIT binary patch literal 5353 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 aFb97BL9ttQLcezZd^E+KGORLiXZ#o3GKAv* literal 0 HcmV?d00001 diff --git a/images/player_small.png b/images/player_small.png new file mode 100644 index 0000000000000000000000000000000000000000..28b55036b9ae9c31a64d844410865a3c7e938d54 GIT binary patch literal 5480 zcmbVQc{o&W-yehQBuds~m)$VTAUjdkkn9tK!OSoQV@bvyMM-5hBH2Pn)(|3OXAonO zEqf%%(mQ^?U(fUY@m$Y)UGKThIrn|;^WE>y_j}*x+%-2fWMSlC1ONamMpyJKDQyMi zQlvjcxnJ^1T&6VKSbbaUb+kJ+2!??JwB69R;DSa-mAM zlWR~{G*T9JLL-Yq`ck+70Ci2AFU-{&jupHG_duXDgf<&ngai?88bUXeP2^2{b>W_f zD}j9 zZ=-BY%msDP7`ULaEJ(&xUO_<+43lgHc!*P6p*K z{6~Tw+}{<0@Wmp~D8Unnuv_Q=tcDQ9(!X6m`kI*hOEAj+pFmMUCWnLh$|=ao%OQ~` ze*H!5kF|vV+l>E6?Qa$A3zxHm`=bLeu9W$37yiRciQRu!bV5k625N>uP$mWDqlb14 zK*CX2BRvfv${SfXgd0>*2c)MDkyi$R73IOI3JR+7svvz3L{9}IucW9X5BVeGKk`E4 zb#(QW^$ZLskyp@H)=`2e=&CB{>nj;3f%N2+|L_{2{IM{UEBudM#EIU&d3FCQFH{!; zhhfneD>T~Y4+6|R(O9&kz( z6C*usE8NtYBa<(uKF@{`&RY@@?F)Kv$*Oz z4P$9{o_Y=LuC^IF+v#BX^LeaCKiDL)!wO}+wuO#gyW$DX;pG7NR}YgaUMxTdD&7S~L1 zb15~+vS)jtxASABiar)wQ)KtLq`R+=lbxO2q|~Z-n912td&fcc#w~4aZOlu%*LvaM zZ(BVq-k=;6!hUWk2FFrSpXzpM4!L`Zg{NqMOV;7Rr&=V3=JC&bKXGC+HAykGs7Qj= z2@s&~6F(%AXZh3u%feQQUyPzX+}tG0W=gE3hU)!2Ub%fZQ-Av) zu$>Cc-TUoJ7t^bobOGraBH#JG?}lzRzX8lL`SdoI?xvPIHugl(vGD{p*yBE3!3`fz zB)#jph9g3ESH@QFhw^tWU7tGmq3XYQO}!Se)fDi`k!=RpY>@#CJKkSfsD!mo*mgXT zvG1VB(X+Kp!~Ogm*BQljSwhS-OTsiu^=4O)OC+rI5&8adpsYwKG&I;n62tPEI#rZH&qVMfME zq(#P@c4_6{LOqw5PD8v|1`x-|Btg}p|L@{%6AJxZ8w8j_Th+&w)pN^=Ead(NGsVVVUwRl`6e z)k2f=rKEu`dTD*_j}LbS`29S^ut_bMng?su+e3yIUXP?Dgfgs}fY_}F^gQ+ygsOr$ z8HK{}RYfu^+EjaRUlmDp^+V>?Mo^kDwcrA|Ey~)r8&Daty8_I*QSRLGc7kJMOWF_y zgI)P%b(u)brY;B#NMQFShKmh#PY-DLlC>bWI_SZHxjCP<6pdr>Tr=)#lhqz()U6h; zy@|2_E$d$OfR)ryD?B2X8Sq1_w)p2|>Z$WGD*T7#o364V{L#T4 z2&e)Ku6{!bNn~$m5F6YtoL^jIjHspM`8+$MR`zb^;nah@4b?lxhl$zH06YJMp2y`A z6~;Xy6ucJSsBm%&rzG%t;HuAPk;R#ks z52E*}?PqP>Oma=+x8k@4J|)l7Q6~6?hh0hhAQv0nG@iKx6dAsP(iJpNi|O;;i}Y{8t-31d}+U@blp7=pGeXR zXpCpl!(gf=-k@`rho2`BhSCFdg+(=$NVqR7L(lY?zEOZxx&axbnQ6iQdb0MA-T}({ z1iw9Y!}(!G!zw?Rz0kxbia1|~Px`dbx}`-o6f^EcsXUrc`SbHnX1|WV%!B~Xm*Y7f zr>3T&@Ej#F8s+>7QVdQyb8lpv>9m|qxs>Kz96x1V4ao2eTmt-{ji`<1ET+VktGc?{ zXwD0kiCU^BGl=5eZWmBIJnP8`qM;|l1fQ)A%EEz|YKG!FXWQunqD3}3(=Z8Ftub)RC2{-ST^I2cBQ zy-8q);i~|uhHIqePZ;8+B)zX&?&aH@@@3ugA0D;MLLG;k>cHy8tPy-K`KiBD(?=-t z5c*rg`ET*xUj@=hmeDso;!{CoB~)<}DA4aA?1?Vj-u@tNJ&xDr1+nhU-f4Np-nZAE ztC`CwUEtru{7%dyqo4=qA+fetKposO(4u|k>M;w( z$2RjP)pz6V!G=1v{_`=a!KDotB*M$fD|PhR3Ej5u)r*=;c#zrFtKgieTh8<`R=gZ2 z$Wh~IsLxK>fDNgNb6FLD0iC^yWl80EIo2+X&jj$Rj0f zVC0llL1AG6#opXttgvmxO@S<;Jv3-TdU6Y*_@PRHtmm5QgUiv*(mb$st8L4?KK$t% zF5)ry@#49z(R~0F{xfm+Ox<^aQrOps|~2+9+2y4S_jITCj1sPlKCJ)lN0nP z%w~HWTWQkm^NlVK}cVCdM-qa@Y=$h}iL+OA{vN0ovK)AO@ zdk_~ia7`i|YA`B$PR5Rt(-Td%G}gcLJBLXrewXjUg^F@r7jJ^L@u1+hL0vXUW#s!I zout}#YP}D-cZ7O;k{B!EWb?S0vHd%0G~B4o)z8n3WEdwEsr{TDb9_HP1amWUT5t>| zEj_p-UynXpmyug4)0zoPCi3O%az&nnyUf+mAF#Wy#{lX(6q3#tD2^>K-FrJvDUdzB zVRxu<#&2hRt>gx|$FuT7B?b;jp__Mm1m{=dnL7Hj)nb+^+@=Ji(Ux=;ysx8cXAuJ8g*GM{#>ypRS0VCSZE-y+ir-)un+ma3H{R$&Z30E z6mmdUk+*?t8YU$b>>_veJ(N!GZ}-YEg@^>c5Ia3_U7mlDt?sd7+LC_qYIRsFh@}Yo zZZG(?576d+A!ye z6P6}}-bA+I!U1J{U1-Hqf4s>bM$~Q|{k~FKK^jU-QjOwV5YEb7q!99aeA(n+VaA_)ywv>KMZvK$zSMfM*S^aI3<5Vb}6uRZ8miZY< zC@+don)f?8obh9n!017Xmg6AKGwU*#&n~|PZe(nnBK!2J&~+}>@sd1+@orEhpR*#TZ! zSOWyW^z;x?(NeS5wDK4=7*)CV*4YIFHinyCC4`e#%->#~WW6A+BO?Pn!^QQYFu^|o zM}Q#KFgM$>n$ohfWxjm*GA4Xef)28-GI%R73Fo-#gw<2&X7(IRO!94D7Ej+^;4`hc zclU1n0tAvj_x!2TnShm12ArlU6a4yU<3D>QTchA$%UOGw)a}JgbO|>nX~`r_Ub{a> z!(N8R^X-m9ipeGH5IdkspjP=cOfnNdU^!71|NG-LL0fyE+mmzr+8r|cZ%Y@l@>J^D zWt=mLa+4p;&Piu!GW1NI)0Tl&h3tC0t`x|93evB$?V&8CNw)3s8E+4NCK%)rT#&)>*6tr~G#@|I?XYcR_sw1X_xGnIC_we7?Lp=+Vbt;xgSmJ(dS+EY~e9r^R>nzZT=dHc8DF zyMp)DCi7P^ptpZvcSXg2Y=hR{SKZ@PG0mvKgTKWP8L8#eb$A*c@X}wxY(>bLK6*va zpPoAuy0f=8aLgH zz^_=GILh!!@jxVP#GZD3o&f`ZZKUV!Q|mlsSdmUiODG3fspxF->ecXrb(Jw&pVa5V zN_0~|s6fNDs6EZWSf09(yw}Rzp_2-~YLTC&cf-~u6lfhrN;776f{iW=kBp23OKb8H z9t%Y8Jqx*0o8RWnn|5)C^)Ay_+M1_J8d4bCMDsHJjj(TrKvL%*mBT|DE~N_@F>$Qb zDYPfwK(F?H+r*HVA2!bPmMQL0~LNNGjb=#d^b%EdM8g^~M!h~LQARFRe80wBHVw7ypg7|aZSz0mZGkWTs^M)BB z=ikU6KvHDnp<>zjY{U{iz$YK9(7L`IgqCe^uzbUD<%;t1>uyP8>hstiMFniSgk0@a ztsn%ti4%H;hv}mm!E2WUDBJdlA547wg|h!aRd@u}FCLE;Uxy=n!qhyecZS^A5W{hl z?~e}=HGQ7CkjNmG*1AvBgdryvSNFuw@Y|XA`!A$zE446fP|V@Id(7!s zS<<0D)+BY|f<0U~!+Ym1)(aAD4umWOjJ=|iz^SeH(zLeB zmQeo&rThJnbop_t{3+V!vtdV8o@^Qk#*qg@-*PWb}GzHIHs!y5<<|Cf!q4VWdY1Q%%Wyr zC00~$RtOK)(q9_0;~?#-Bd3(260Zuo*m$3&yNA3~!V61ac9D*3NLz*fN-UNicsbtt zvyWCS?aRmNxnN0$vWWtgH(#5R>&*+dQj~sc08HWpBAv#&b^>@lZr@J7;~sL4w6`)= zy8Q{=V*Nc9;uNC(Wb-xA=~15Nmnz&F{DSV53}V1?Bvz3I4Ni?Z^VJSim-N(T;7FR) zmh5or>2K@Lkwcg=o6*Dl9W)oth`X$txzRxUw^&4TqZg(_tM%m?dAHWNs430=g%R}; zN&hYdz@y}@Kuh?dxn$R2{TzhrqDbe(Z1PmC%`m?InQ)TonOk#xF#is!3QC_G(7{ew gD5t+}J5y19oWlJudlSz-o&5VW(l^yB*KvvbAKlLO=Kufz literal 0 HcmV?d00001 diff --git a/images/progress_indicator.png b/images/progress_indicator.png new file mode 100644 index 0000000000000000000000000000000000000000..b086d0a7ad014a6f304d4efb484e623fbb3a74d5 GIT binary patch literal 1594 zcmeAS@N?(olHy`uVBq!ia0vp^Vn8gx!3HG%?c?8U}fi7AzZCsS=07?@QuLn2Bde0{8v^Kf6`()~Xj@TAnpKdC8`Lf!&sHg;q@=(~U%$M( zT(8_%FTW^V-_X+15@d#vkuFe$ZgFK^Nn(X=Ua>OF1ees}+T7#d8#0MoBXEYLU9GXQxBrqI_HztY@Xxa#7Ppj3o=u^L<)Qdy9y zACy|0Us{w5jJPyqkW~d%&PAz-CHX}m`T04pPz=b(FUc>?$S+WE4mMNJ@J&q4%mWE% zf_3=%T6yLbmn7yTr+T{BDgn*V%gju%a&|K{F*LJqc5}8gHZ*iKb#gH`b~3SWbhU6b zGB-7`fa!I~PcF?(%`1WFO+n~&!KoLN7;+1MHoK%2WtOF;xE1B+Du6w0m5JLejyTPO z>P^Az7AKr~^?{Dj2SqJXRKtXT=?BDwCtM&0p7c}mfa$#mn6R4!;(?ipX^p3gV@SoV zEmO~T2L*~8zu*7*g>*&g`b8W%T;}h%<}@zwoyn5dbfEq~UCt!2cS5Y0Y*B1_P5)YE zrY3AI5IuWou6Acql*`fuk7n%q_;<(L&o<%jPDt$faA^AX*Z0m_e!ug6um96I+OIQa zZCbX?Y{RYxu>tc_j3mQCzp~wlDo8CTU07nf<6nk}l-bn6Yw=q)pOQXv;B(E=0F4~S z_Sg&Ib-QYr_v(sumv5BMs(beN!GmNSvEbKVe;J?Q(KIla@Vct;!@OH7ZszRsQW5%P z6T`OpOW^veS^kA0PHMvCY?Gf_TvoWD&^dkAI%BO)D}KI3&x$PP)J31mn<((kBBJQt z+2^0XD@{D1lg)TcLu$%_S6_F%|Hp3az3=_!iy0xk#~)8SA$4$8MMKBNj4y{Khvq)5 zj4|YSZ1`f?8xzKBx~F&XG$v{PF3q~}de*X7r#>FH)YBKI!;`g>0xZ0G({(~i0(`Gg;Ew6{GkeL8MlWAxf< z^A|6Ee|D)cn?_DCYkFnHkEg}UFK2ceb%-t6{2*f z=3#PA(xX#N+sexBg%oJ|em2qme?HU&6KDL;s7@T7BePPX?qwzC#VZR+G`+wF} z)eZiUa|7DUPKsV|-LE!rr(Y7w)ulbLLTn#AmM?JBy!Q3?fAs?lcf&(Hk9|3{6jYjf My85}Sb4q9e0GMlYd;kCd literal 0 HcmV?d00001 diff --git a/images/statbar.png b/images/statbar.png new file mode 100644 index 0000000000000000000000000000000000000000..3bd291583475fb49876f238399c7024bf1dd7ec9 GIT binary patch literal 1380 zcmaJ>e@q)?82$!07aT(r$TlZCi^dV?k1K6yFLX_5%jiOpmFjAO8^`quC)^M3jHnsT{Cw<8}TSXzNg7=@qaARB;elb^$h3Q|N$$uf#D%I5n9 zWeDXl$_{EBDhFpF%c;BoPZk9VTtuLPFnDC9y-2nng90=u;)tKFWCYA_lr8IGa4dzD zGGrMdRv2X~rreG~#KQ6r(86h>IU?l~D zr#O*f8AMXVOW7*XD1%N{N}#zlSw>i0Cb(cqKh7ypg-R+Z0(3b3A4=0}XhC$65B#nx zEV!yUQt2cGwu&d<#(7hvR2*jENnB)k7t2;gRF}B;gRUYsLe60Vt4Z1+T)LgwwfP0_F3}hk6npTG+yiQ zj()Ltcs^xltoiR(Z@nM-*=5qPw9m(oS9YN&hSWuPr$TLh5mO`1Q)xM~Jq5pRwKfaY^we z09@1US+1Vu+Z}BMwV%BEmT7A`L_ZPVmft;bBgU+ng;xOBX6b&ubn~&xErI?+MF$6W z!&D`v-kYwO?qJ>UkH5Xp+VG{f^QyPg&@rj*lHA3mPcWC1`#$_?c8XgZyL+T>ravw? zQTflEg})XIsW8FIwP=r^NUNF7uQ+>`Nle1Gd*eU-MK>G`Kxh!zGC44B`aRJ9{Z;Dd zg|kKX#zvv&9Mw~tlC`tWH`DB{l}tv5CW9H*4sCxk34o!gk)dD%8;afWVzCS4I)DzmK{K?jdJ5BW;jLcNG uC%^)%>nt*rSu^HzCAT?xocYu3= 256 || typeof arg[i] !== 'number') { + throw new Error('invalid byte at index ' + i + '(' + arg[i] + ')'); + } + } + + // Most array-like things should support this + if (arg.slice) { + return arg.slice(0); + } + + // Something *weird*; copy it into an array (see PR#2) + var result = []; + for (var i = 0; i < arg.length; i++) { + result.push(arg[i]); + } + return result; + } + } + + if (typeof(Buffer) === 'undefined') { + createBuffer = slowCreateBuffer; + + copyBuffer = function(sourceBuffer, targetBuffer, targetStart, sourceStart, sourceEnd) { + if (targetStart == null) { targetStart = 0; } + if (sourceStart == null) { sourceStart = 0; } + if (sourceEnd == null) { sourceEnd = sourceBuffer.length; } + for (var i = sourceStart; i < sourceEnd; i++) { + targetBuffer[targetStart++] = sourceBuffer[i]; + } + } + + convertStringToBytes = function(text, encoding) { + + // "utf8", "utf-8", "utf 8", etc + if (encoding == null || encoding.toLowerCase().replace(/ |-/g, "") == 'utf8') { + var result = [], i = 0; + text = encodeURI(text); + while (i < text.length) { + var c = text.charCodeAt(i++); + + // if it is a % sign, encode the following 2 bytes as a hex value + if (c === 37) { + result.push(parseInt(text.substr(i, 2), 16)) + i += 2; + + // otherwise, just the actual byte + } else { + result.push(c) + } + } + + return result; + + // "hex" + } else if (encoding.toLowerCase() == 'hex') { + var result = []; + for (var i = 0; i < text.length; i += 2) { + result.push(parseInt(text.substr(i, 2), 16)); + } + + return result; + } + + // @TODO: Base64... + + return null; + } + + // http://ixti.net/development/javascript/2011/11/11/base64-encodedecode-of-utf8-in-browser-with-js.html + var Hex = '0123456789abcdef'; + convertBytesToString = function(bytes, encoding) { + + // "utf8", "utf-8", "utf 8", etc + if (encoding == null || encoding.toLowerCase().replace(/ |-/g, "") == 'utf8') { + var result = [], i = 0; + + while (i < bytes.length) { + var c = bytes[i]; + + if (c < 128) { + result.push(String.fromCharCode(c)); + i++; + } else if (c > 191 && c < 224) { + result.push(String.fromCharCode(((c & 0x1f) << 6) | (bytes[i + 1] & 0x3f))); + i += 2; + } else { + result.push(String.fromCharCode(((c & 0x0f) << 12) | ((bytes[i + 1] & 0x3f) << 6) | (bytes[i + 2] & 0x3f))); + i += 3; + } + } + + return result.join(''); + + // "hex" + } else if (encoding.toLowerCase() == 'hex') { + var result = []; + for (var i = 0; i < bytes.length; i++) { + var v = bytes[i]; + result.push(Hex[(v & 0xf0) >> 4] + Hex[v & 0x0f]); + } + return result.join(''); + } + + return result + } + + } else { + createBuffer = function(arg) { return new Buffer(arg); } + + copyBuffer = function(sourceBuffer, targetBuffer, targetStart, sourceStart, sourceEnd) { + sourceBuffer.copy(targetBuffer, targetStart, sourceStart, sourceEnd); + } + + convertStringToBytes = function(text, encoding) { + return new Buffer(text, encoding); + } + + convertBytesToString = function(bytes, encoding) { + return (new Buffer(bytes)).toString(encoding); + } + } + + + // Number of rounds by keysize + var numberOfRounds = {16: 10, 24: 12, 32: 14} + + // Round constant words + var rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91]; + + // S-box and Inverse S-box (S is for Substitution) + var S = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16]; + var Si =[0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d]; + + // Transformations for encryption + var T1 = [0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a]; + var T2 = [0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616]; + var T3 = [0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16]; + var T4 = [0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c]; + + // Transformations for decryption + var T5 = [0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742]; + var T6 = [0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857]; + var T7 = [0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8]; + var T8 = [0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0]; + + // Transformations for decryption key expansion + var U1 = [0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3]; + var U2 = [0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39, 0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165, 0x4e6c5a72, 0x4562537f, 0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd, 0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4, 0x97d6bde9, 0x8ac4a6fe, 0x81caaff3, 0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581, 0xd2b4ee96, 0xd9bae79b, 0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac, 0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade, 0x35b761c9, 0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0, 0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652, 0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814, 0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d, 0xfda37f60, 0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e, 0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512, 0x82e51a31, 0x89eb133c, 0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa, 0x6a75c289, 0x617bcb84, 0x7c69d093, 0x7767d99e, 0x1e3daed5, 0x1533a7d8, 0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6, 0x8d764dd6, 0x867844db, 0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef, 0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9, 0xf93e218a, 0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b, 0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225, 0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857, 0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0, 0xea53f7cd, 0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf, 0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b, 0x9515929c, 0x9e1b9b91, 0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133, 0x7d854a24, 0x768b4329, 0x1fd13462, 0x14df3d6f, 0x09cd2678, 0x02c32f75, 0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c, 0x9a86c57b, 0x9188cc76, 0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842, 0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230, 0xeecea927, 0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6, 0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4, 0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa, 0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83, 0x26dab78e, 0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8, 0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc, 0xb10c0a67, 0xba02036a, 0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544, 0xe97c420f, 0xe2724b02, 0xff605015, 0xf46e5918, 0xc544663b, 0xce4a6f36, 0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b, 0x560f8538, 0x5d018c35, 0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069, 0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647, 0xcad731dc, 0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5, 0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3, 0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697]; + var U3 = [0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d, 0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41, 0x724e6c5a, 0x7f456253, 0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99, 0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4, 0xe997d6bd, 0xfe8ac4a6, 0xf381caaf, 0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5, 0x96d2b4ee, 0x9bd9bae7, 0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920, 0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a, 0xc935b761, 0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c, 0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86, 0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8, 0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76, 0x60fda37f, 0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749, 0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25, 0x3182e51a, 0x3c89eb13, 0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd, 0x896a75c2, 0x84617bcb, 0x937c69d0, 0x9e7767d9, 0xd51e3dae, 0xd81533a7, 0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791, 0xd68d764d, 0xdb867844, 0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060, 0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e, 0x8af93e21, 0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4, 0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2, 0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8, 0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe, 0xcdea53f7, 0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad, 0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789, 0x9c951592, 0x919e1b9b, 0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751, 0x247d854a, 0x29768b43, 0x621fd134, 0x6f14df3d, 0x7809cd26, 0x7502c32f, 0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de, 0x7b9a86c5, 0x769188cc, 0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8, 0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2, 0x27eecea9, 0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c, 0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406, 0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030, 0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be, 0x8e26dab7, 0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9, 0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed, 0x67b10c0a, 0x6aba0203, 0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635, 0x0fe97c42, 0x02e2724b, 0x15ff6050, 0x18f46e59, 0x3bc54466, 0x36ce4a6f, 0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba, 0x38560f85, 0x355d018c, 0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0, 0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6, 0xdccad731, 0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c, 0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562, 0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46]; + var U4 = [0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562, 0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca, 0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba, 0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9, 0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5, 0x61c935b7, 0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281, 0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d, 0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59, 0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad, 0x7f60fda3, 0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787, 0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf, 0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f, 0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767, 0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17, 0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814, 0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc, 0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53, 0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b, 0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b, 0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3, 0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188, 0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0, 0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc, 0xa927eece, 0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168, 0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04, 0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520, 0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4, 0xb78e26da, 0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e, 0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6, 0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026, 0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e, 0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725, 0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d, 0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5, 0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d]; + + + function convertToInt32(bytes) { + var result = []; + for (var i = 0; i < bytes.length; i += 4) { + result.push( + (bytes[i ] << 24) | + (bytes[i + 1] << 16) | + (bytes[i + 2] << 8) | + bytes[i + 3] + ); + } + return result; + } + + + + + var AES = function(key) { + this.key = createBuffer(key); + this._prepare(); + } + + + AES.prototype._prepare = function() { + + var rounds = numberOfRounds[this.key.length]; + if (rounds == null) { + throw new Error('invalid key size (must be length 16, 24 or 32)'); + } + + // encryption round keys + this._Ke = []; + + // decryption round keys + this._Kd = []; + + for (var i = 0; i <= rounds; i++) { + this._Ke.push([0, 0, 0, 0]); + this._Kd.push([0, 0, 0, 0]); + } + + var roundKeyCount = (rounds + 1) * 4; + var KC = this.key.length / 4; + + // convert the key into ints + var tk = convertToInt32(this.key); + + // copy values into round key arrays + var index; + for (var i = 0; i < KC; i++) { + index = i >> 2; + this._Ke[index][i % 4] = tk[i]; + this._Kd[rounds - index][i % 4] = tk[i]; + } + + // key expansion (fips-197 section 5.2) + var rconpointer = 0; + var t = KC, tt; + while (t < roundKeyCount) { + tt = tk[KC - 1]; + tk[0] ^= ((S[(tt >> 16) & 0xFF] << 24) ^ + (S[(tt >> 8) & 0xFF] << 16) ^ + (S[ tt & 0xFF] << 8) ^ + S[(tt >> 24) & 0xFF] ^ + (rcon[rconpointer] << 24)); + rconpointer += 1; + + // key expansion (for non-256 bit) + if (KC != 8) { + for (var i = 1; i < KC; i++) { + tk[i] ^= tk[i - 1]; + } + + // key expansion for 256-bit keys is "slightly different" (fips-197) + } else { + for (var i = 1; i < (KC / 2); i++) { + tk[i] ^= tk[i - 1]; + } + tt = tk[(KC / 2) - 1]; + + tk[KC / 2] ^= (S[ tt & 0xFF] ^ + (S[(tt >> 8) & 0xFF] << 8) ^ + (S[(tt >> 16) & 0xFF] << 16) ^ + (S[(tt >> 24) & 0xFF] << 24)); + + for (var i = (KC / 2) + 1; i < KC; i++) { + tk[i] ^= tk[i - 1]; + } + } + + // copy values into round key arrays + var i = 0, r, c; + while (i < KC && t < roundKeyCount) { + r = t >> 2; + c = t % 4; + this._Ke[r][c] = tk[i]; + this._Kd[rounds - r][c] = tk[i++]; + t++; + } + } + + // inverse-cipher-ify the decryption round key (fips-197 section 5.3) + for (var r = 1; r < rounds; r++) { + for (var c = 0; c < 4; c++) { + tt = this._Kd[r][c]; + this._Kd[r][c] = (U1[(tt >> 24) & 0xFF] ^ + U2[(tt >> 16) & 0xFF] ^ + U3[(tt >> 8) & 0xFF] ^ + U4[ tt & 0xFF]); + } + } + } + + AES.prototype.encrypt = function(plaintext) { + if (plaintext.length != 16) { + return new Error('plaintext must be a block of size 16'); + } + + var rounds = this._Ke.length - 1; + var a = [0, 0, 0, 0]; + + // convert plaintext to (ints ^ key) + var t = convertToInt32(plaintext); + for (var i = 0; i < 4; i++) { + t[i] ^= this._Ke[0][i]; + } + + // apply round transforms + for (var r = 1; r < rounds; r++) { + for (var i = 0; i < 4; i++) { + a[i] = (T1[(t[ i ] >> 24) & 0xff] ^ + T2[(t[(i + 1) % 4] >> 16) & 0xff] ^ + T3[(t[(i + 2) % 4] >> 8) & 0xff] ^ + T4[ t[(i + 3) % 4] & 0xff] ^ + this._Ke[r][i]); + } + t = a.slice(0); + } + + // the last round is special + var result = createBuffer(16), tt; + for (var i = 0; i < 4; i++) { + tt = this._Ke[rounds][i]; + result[4 * i ] = (S[(t[ i ] >> 24) & 0xff] ^ (tt >> 24)) & 0xff; + result[4 * i + 1] = (S[(t[(i + 1) % 4] >> 16) & 0xff] ^ (tt >> 16)) & 0xff; + result[4 * i + 2] = (S[(t[(i + 2) % 4] >> 8) & 0xff] ^ (tt >> 8)) & 0xff; + result[4 * i + 3] = (S[ t[(i + 3) % 4] & 0xff] ^ tt ) & 0xff; + } + + return result; + } + + AES.prototype.decrypt = function(ciphertext) { + if (ciphertext.length != 16) { + return new Error('ciphertext must be a block of size 16'); + } + + var rounds = this._Kd.length - 1; + var a = [0, 0, 0, 0]; + + // convert plaintext to (ints ^ key) + var t = convertToInt32(ciphertext); + for (var i = 0; i < 4; i++) { + t[i] ^= this._Kd[0][i]; + } + + // apply round transforms + for (var r = 1; r < rounds; r++) { + for (var i = 0; i < 4; i++) { + a[i] = (T5[(t[ i ] >> 24) & 0xff] ^ + T6[(t[(i + 3) % 4] >> 16) & 0xff] ^ + T7[(t[(i + 2) % 4] >> 8) & 0xff] ^ + T8[ t[(i + 1) % 4] & 0xff] ^ + this._Kd[r][i]); + } + t = a.slice(0); + } + + // the last round is special + var result = createBuffer(16), tt; + for (var i = 0; i < 4; i++) { + tt = this._Kd[rounds][i]; + result[4 * i ] = (Si[(t[ i ] >> 24) & 0xff] ^ (tt >> 24)) & 0xff; + result[4 * i + 1] = (Si[(t[(i + 3) % 4] >> 16) & 0xff] ^ (tt >> 16)) & 0xff; + result[4 * i + 2] = (Si[(t[(i + 2) % 4] >> 8) & 0xff] ^ (tt >> 8)) & 0xff; + result[4 * i + 3] = (Si[ t[(i + 1) % 4] & 0xff] ^ tt ) & 0xff; + } + + return result; + } + + + /** + * Mode Of Operation - Electonic Codebook (ECB) + */ + var ModeOfOperationECB = function(key) { + this.description = "Electronic Code Block"; + this.name = "ecb"; + + this._aes = new AES(key); + } + + ModeOfOperationECB.prototype.encrypt = function(plaintext) { + return this._aes.encrypt(plaintext); + } + + ModeOfOperationECB.prototype.decrypt = function(ciphertext, encoding) { + return this._aes.decrypt(ciphertext); + } + + + /** + * Mode Of Operation - Cipher Block Chaining (CBC) + */ + var ModeOfOperationCBC = function(key, iv) { + this.description = "Cipher Block Chaining"; + this.name = "cbc"; + + if (!iv) { + iv = createBuffer([0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + + } else if (iv.length != 16) { + return new Error('initialation vector iv must be of length 16'); + } + + this._lastCipherblock = createBuffer(iv); + + this._aes = new AES(key); + } + + ModeOfOperationCBC.prototype.encrypt = function(plaintext) { + if (plaintext.length != 16) { + return new Error('plaintext must be a block of size 16'); + } + + var precipherblock = createBuffer(plaintext); + for (var i = 0; i < 16; i++) { + precipherblock[i] ^= this._lastCipherblock[i]; + } + + this._lastCipherblock = this._aes.encrypt(precipherblock); + + return this._lastCipherblock; + } + + ModeOfOperationCBC.prototype.decrypt = function(ciphertext) { + if (ciphertext.length != 16) { + return new Error('ciphertext must be a block of size 16'); + } + + var plaintext = this._aes.decrypt(ciphertext); + for (var i = 0; i < 16; i++) { + plaintext[i] ^= this._lastCipherblock[i]; + } + + copyBuffer(ciphertext, this._lastCipherblock); + + return plaintext; + } + + + /** + * Mode Of Operation - Cipher Feedback (CFB) + */ + var ModeOfOperationCFB = function(key, iv, segmentSize) { + this.description = "Cipher Feedback"; + this.name = "cfb"; + + if (!iv) { + iv = createBuffer([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + + } else if (iv.length != 16) { + return new Error('initialation vector iv must be of length 16'); + } + + if (!segmentSize) { segmentSize = 1; } + + this.segmentSize = segmentSize; + + this._shiftRegister = createBuffer(iv); + + this._aes = new AES(key); + } + + ModeOfOperationCFB.prototype.encrypt = function(plaintext) { + if ((plaintext.length % this.segmentSize) != 0) { + return new Error('plaintext must be a block of size module segmentSize (' + this.segmentSize + ')'); + } + + var encrypted = createBuffer(plaintext); + + var xorSegment; + for (var i = 0; i < encrypted.length; i += this.segmentSize) { + xorSegment = this._aes.encrypt(this._shiftRegister); + for (var j = 0; j < this.segmentSize; j++) { + encrypted[i + j] ^= xorSegment[j]; + } + + // Shift the register + copyBuffer(this._shiftRegister, this._shiftRegister, 0, this.segmentSize); + copyBuffer(encrypted, this._shiftRegister, 16 - this.segmentSize, i, i + this.segmentSize); + } + + return encrypted; + } + + ModeOfOperationCFB.prototype.decrypt = function(ciphertext) { + if ((ciphertext.length % this.segmentSize) != 0) { + return new Error('ciphertext must be a block of size module segmentSize (' + this.segmentSize + ')'); + } + + var plaintext = createBuffer(ciphertext); + + var xorSegment; + for (var i = 0; i < plaintext.length; i += this.segmentSize) { + xorSegment = this._aes.encrypt(this._shiftRegister); + + for (var j = 0; j < this.segmentSize; j++) { + plaintext[i + j] ^= xorSegment[j]; + } + + // Shift the register + copyBuffer(this._shiftRegister, this._shiftRegister, 0, this.segmentSize); + copyBuffer(ciphertext, this._shiftRegister, 16 - this.segmentSize, i, i + this.segmentSize); + } + + return plaintext; + } + + /** + * Mode Of Operation - Output Feedback (OFB) + */ + var ModeOfOperationOFB = function(key, iv) { + this.description = "Output Feedback"; + this.name = "ofb"; + + if (!iv) { + iv = createBuffer([0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + + } else if (iv.length != 16) { + return new Error('initialation vector iv must be of length 16'); + } + + this._lastPrecipher = createBuffer(iv); + this._lastPrecipherIndex = 16; + + this._aes = new AES(key); + } + + ModeOfOperationOFB.prototype.encrypt = function(plaintext) { + var encrypted = createBuffer(plaintext); + + for (var i = 0; i < encrypted.length; i++) { + if (this._lastPrecipherIndex === 16) { + this._lastPrecipher = this._aes.encrypt(this._lastPrecipher); + this._lastPrecipherIndex = 0; + } + encrypted[i] ^= this._lastPrecipher[this._lastPrecipherIndex++]; + } + + return encrypted; + } + + // Decryption is symetric + ModeOfOperationOFB.prototype.decrypt = ModeOfOperationOFB.prototype.encrypt; + + + /** + * Counter object for CTR common mode of operation + */ + var Counter = function(initialValue) { + // We allow 0, but anything false-ish uses the default 1 + if (initialValue !== 0 && !initialValue) { initialValue = 1; } + + if (typeof(initialValue) === 'number') { + this._counter = createBuffer([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + this.setValue(initialValue); + + } else { + this.setBytes(initialValue); + } + } + + Counter.prototype.setValue = function(value) { + if (typeof(value) !== 'number' || parseInt(value) != value) { + throw new Error('value must be an integer'); + } + + for (var index = 15; index >= 0; --index) { + this._counter[index] = value % 256; + value = value >> 8; + } + } + + Counter.prototype.setBytes = function(bytes) { + if (bytes.length != 16) { + throw new Error('invalid counter bytes size (must be 16)'); + } + this._counter = createBuffer(bytes); + }; + + Counter.prototype.increment = function() { + for (var i = 15; i >= 0; i--) { + if (this._counter[i] === 255) { + this._counter[i] = 0; + } else { + this._counter[i]++; + break; + } + } + } + + + /** + * Mode Of Operation - Counter (CTR) + */ + var ModeOfOperationCTR = function(key, counter) { + this.description = "Counter"; + this.name = "ctr"; + + if (!(counter instanceof Counter)) { + counter = new Counter(counter) + } + + this._counter = counter; + + this._remainingCounter = null; + this._remainingCounterIndex = 16; + + this._aes = new AES(key); + } + + ModeOfOperationCTR.prototype.encrypt = function(plaintext) { + var encrypted = createBuffer(plaintext); + + for (var i = 0; i < encrypted.length; i++) { + if (this._remainingCounterIndex === 16) { + this._remainingCounter = this._aes.encrypt(this._counter._counter); + this._remainingCounterIndex = 0; + this._counter.increment(); + } + encrypted[i] ^= this._remainingCounter[this._remainingCounterIndex++]; + } + + return encrypted; + } + + // Decryption is symetric + ModeOfOperationCTR.prototype.decrypt = ModeOfOperationCTR.prototype.encrypt; + + + // The bsic modes of operation as a map + var ModeOfOperation = { + ecb: ModeOfOperationECB, + cbc: ModeOfOperationCBC, + cfb: ModeOfOperationCFB, + ofb: ModeOfOperationOFB, + ctr: ModeOfOperationCTR + }; + + + /////////////////////// + // Exporting + + + // The block cipher + var aesjs = { + AES: AES, + Counter: Counter, + ModeOfOperation: ModeOfOperation, + util: { + convertBytesToString: convertBytesToString, + convertStringToBytes: convertStringToBytes, + _slowCreateBuffer: slowCreateBuffer + } + }; + + + // node.js + if (typeof exports !== 'undefined') { + module.exports = aesjs + + // RequireJS/AMD + // http://www.requirejs.org/docs/api.html + // https://github.com/amdjs/amdjs-api/wiki/AMD + } else if (typeof(define) === 'function' && define.amd) { + define(aesjs); + + // Web Browsers + } else { + + // If there was an existing library at "aes" make sure it's still available + if (root.aes) { + aesjs._aes = root.aes; + } + + root.aesjs = aesjs; + } + + +})(this); \ No newline at end of file diff --git a/js/app.js b/js/app.js new file mode 100644 index 0000000..c5ff23e --- /dev/null +++ b/js/app.js @@ -0,0 +1,806 @@ +(function() { + 'use strict'; + + Storage.prototype.setObject = function(key, value) { + this.setItem(key, JSON.stringify(value)); + } + + Storage.prototype.getObject = function(key) { + var value = this.getItem(key); + return value && JSON.parse(value); + } + + var app = angular.module('listenone', ['angularSoundManager', 'ui-notification', 'loWebManager']) + .config( [ + '$compileProvider', + function( $compileProvider ) + { + $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|mailto|chrome-extension):/); + } + ]); + + app.config(function(NotificationProvider) { + NotificationProvider.setOptions({ + delay: 2000, + startTop: 20, + startRight: 10, + verticalSpacing: 20, + horizontalSpacing: 20, + positionX: 'center', + positionY: 'top' + }); + }); + + app.filter('playmode_title', function() { + return function(input) { + return input ? '随机' : '顺序'; + }; + }); + + // control main view of page, it can be called any place + app.controller('NavigationController', ['$scope', '$http', + '$httpParamSerializerJQLike', '$timeout', + 'angularPlayer', 'Notification', '$rootScope', 'loWeb', + function($scope, $http, $httpParamSerializerJQLike, + $timeout, angularPlayer, Notification, $rootScope, loWeb){ + $scope.window_url_stack = []; + $scope.current_tag = 2; + $scope.is_window_hidden = 1; + $scope.is_dialog_hidden = 1; + + $scope.songs = []; + $scope.current_list_id = -1; + + $scope.dialog_song = ''; + $scope.dialog_type = 0; + $scope.dialog_title = ''; + + $scope.isDoubanLogin = false; + $scope.$on('isdoubanlogin:update', function(event, data) { + $scope.isDoubanLogin = data; + }); + + // tag + $scope.showTag = function(tag_id){ + $scope.current_tag = tag_id; + $scope.is_window_hidden = 1; + $scope.window_url_stack = []; + $scope.closeWindow(); + }; + + // playlist window + $scope.resetWindow = function() { + $scope.cover_img_url = 'images/loading.gif'; + $scope.playlist_title = ''; + $scope.songs = []; + }; + + $scope.showWindow = function(url){ + $scope.is_window_hidden = 0; + $scope.resetWindow(); + + $scope.window_url_stack.push(url); + loWeb.get(url).success(function(data) { + if (data.status == '0') { + Notification.info(data.reason); + $scope.popWindow(); + return; + } + $scope.songs = data.tracks; + $scope.cover_img_url = data.info.cover_img_url; + $scope.playlist_title = data.info.title; + $scope.list_id = data.info.id; + $scope.is_mine = data.is_mine; + }); + }; + + $scope.closeWindow = function(){ + $scope.is_window_hidden = 1; + $scope.resetWindow(); + $scope.window_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]; + loWeb.get(url).success(function(data) { + $scope.songs = data.tracks; + $scope.cover_img_url = data.info.cover_img_url; + $scope.playlist_title = data.info.title; + }); + } + }; + + $scope.showPlaylist = function(list_id) { + var url = '/playlist?list_id=' + list_id; + $scope.showWindow(url); + }; + + $scope.showArtist = function(artist_id) { + var url = '/artist?artist_id=' + artist_id; + $scope.showWindow(url); + }; + + $scope.showAlbum = function(album_id) { + var url = '/album?album_id=' + album_id; + $scope.showWindow(url); + }; + + $scope.directplaylist = function(list_id){ + var url = '/playlist?list_id=' + list_id; + + loWeb.get(url).success(function(data) { + $scope.songs = data.tracks; + $scope.current_list_id = list_id; + + $timeout(function(){ + // use timeout to avoid stil in digest error. + angularPlayer.clearPlaylist(function(data) { + //add songs to playlist + angularPlayer.addTrackArray($scope.songs); + //play first song + var index = 0; + if (angularPlayer.getShuffle()) { + var max = $scope.songs.length - 1; + var min = 0; + index = Math.floor(Math.random() * (max - min + 1)) + min; + } + angularPlayer.playTrack($scope.songs[index].id); + + }); + }, 0); + }); + }; + + $scope.showDialog = function(dialog_type, data) { + $scope.is_dialog_hidden = 0; + var dialogWidth = 480; + var left = $(window).width()/2 - dialogWidth/2; + $scope.myStyle = {'left': left + 'px'}; + + if (dialog_type == 0) { + $scope.dialog_title = '添加到歌单'; + var url = '/show_myplaylist'; + $scope.dialog_song = data; + $http.get(url).success(function(data) { + $scope.myplaylist = data.result; + }); + } + + if (dialog_type == 2) { + $scope.dialog_title = '登录豆瓣'; + $scope.dialog_type = 2; + } + }; + + $scope.chooseDialogOption = function(option_id) { + var url = '/add_myplaylist'; + + $http({ + url: url, + method: 'POST', + data: $httpParamSerializerJQLike({ + list_id: option_id, + id: $scope.dialog_song.id, + title: $scope.dialog_song.title, + artist: $scope.dialog_song.artist, + url: $scope.dialog_song.url, + artist_id: $scope.dialog_song.artist_id, + album: $scope.dialog_song.album, + album_id: $scope.dialog_song.album_id, + source: $scope.dialog_song.source, + source_url: $scope.dialog_song.source_url + }), + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }).success(function() { + Notification.success('添加到歌单成功'); + $scope.closeDialog(); + // add to current playing list + if (option_id == $scope.current_list_id) { + angularPlayer.addTrack($scope.dialog_song); + } + }); + }; + + $scope.newDialogOption = function() { + $scope.dialog_type = 1; + }; + + $scope.cancelNewDialog = function() { + $scope.dialog_type = 0; + }; + + $scope.createAndAddPlaylist = function() { + var url = '/create_myplaylist'; + + $http({ + url: url, + method: 'POST', + data: $httpParamSerializerJQLike({ + list_title: $scope.newlist_title, + id: $scope.dialog_song.id, + title: $scope.dialog_song.title, + artist: $scope.dialog_song.artist, + url: $scope.dialog_song.url, + artist_id: $scope.dialog_song.artist_id, + album: $scope.dialog_song.album, + album_id: $scope.dialog_song.album_id, + source: $scope.dialog_song.source, + source_url: $scope.dialog_song.source_url + }), + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }).success(function() { + $rootScope.$broadcast('myplaylist:update'); + Notification.success('添加到歌单成功'); + $scope.closeDialog(); + }); + }; + + $scope.removeSongFromPlaylist = function(song, list_id) { + var url = '/remove_track_from_myplaylist'; + + $http({ + url: url, + method: 'POST', + data: $httpParamSerializerJQLike({ + list_id: list_id, + track_id: song.id + }), + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }).success(function() { + // remove song from songs + var index = $scope.songs.indexOf(song); + if (index > -1) { + $scope.songs.splice(index, 1); + } + Notification.success('删除成功'); + }); + } + + $scope.closeDialog = function() { + $scope.is_dialog_hidden = 1; + $scope.dialog_type = 0; + }; + + $scope.setCurrentList = function(list_id) { + $scope.current_list_id = list_id; + }; + + $scope.$on('player:playlist', function(event, data) { + localStorage.setObject('current-playing', data); + }); + + $scope.$on('track:id', function(event, data) { + var current = localStorage.getObject('player-settings'); + current.nowplaying_track_id = data; + localStorage.setObject('player-settings', current); + }); + }]); + + + app.controller('PlayController', ['$scope', '$timeout','$log', + '$anchorScroll', '$location', 'angularPlayer', '$http', + '$httpParamSerializerJQLike','$rootScope', 'Notification','loWeb', + function($scope, $timeout, $log, $anchorScroll, $location, angularPlayer, + $http, $httpParamSerializerJQLike, $rootScope, Notification, loWeb){ + $scope.menuHidden = true; + + $scope.settings = {"playmode": 0, "nowplaying_track_id": -1}; + + $scope.loadLocalSettings = function() { + var defaultSettings = {"playmode": 0, "nowplaying_track_id": -1} + var localSettings = localStorage.getObject('player-settings'); + if (localSettings == null) { + $scope.settings = {"playmode": 0, "nowplaying_track_id": -1}; + $scope.saveLocalSettings(); + } + else { + $scope.settings = localSettings; + } + // apply settings + var shuffleSetting; + if ($scope.settings.playmode == 1) { + shuffleSetting = true; + } + else { + shuffleSetting = false; + } + if (angularPlayer.getShuffle() != shuffleSetting) { + angularPlayer.toggleShuffle(); + } + } + + $scope.saveLocalSettings = function() { + localStorage.setObject('player-settings', $scope.settings); + } + + $scope.loadLocalCurrentPlaying = function() { + var localSettings = localStorage.getObject('current-playing'); + if (localSettings == null) { + return; + } + // apply local current playing; + angularPlayer.addTrackArray(localSettings); + } + + $scope.saveLocalCurrentPlaying = function() { + localStorage.setObjct('current-playing', angularPlayer.playlist) + } + + $scope.changePlaymode = function() { + // loop: 0, shuffle: 1 + angularPlayer.toggleShuffle(); + if (angularPlayer.getShuffle()) { + $scope.settings.playmode = 1; + } + else { + $scope.settings.playmode = 0; + } + $scope.saveLocalSettings(); + }; + + $scope.$on('angularPlayer:ready', function(event, data) { + $log.debug('cleared, ok now add to playlist'); + if (angularPlayer.getRepeatStatus() == false) { + angularPlayer.repeatToggle(); + } + $timeout(function(){angularPlayer.setBootstrapTrack(loWeb.bootstrapTrack);}, 0); + + if (track_id == -1) { + return; + } + + //add songs to playlist + var localCurrentPlaying = localStorage.getObject('current-playing'); + if (localCurrentPlaying == null) { + return; + } + angularPlayer.addTrackArray(localCurrentPlaying); + + var localPlayerSettings = localStorage.getObject('player-settings'); + if (localPlayerSettings == null) { + return; + } + var track_id = localPlayerSettings.nowplaying_track_id; + + angularPlayer.playTrack(track_id); + angularPlayer.pause(); + + }); + + $scope.gotoAnchor = function(newHash) { + if ($location.hash() !== newHash) { + // set the $location.hash to `newHash` and + // $anchorScroll will automatically scroll to it + $location.hash(newHash); + $anchorScroll(); + } else { + // call $anchorScroll() explicitly, + // since $location.hash hasn't changed + $anchorScroll(); + } + }; + + $scope.togglePlaylist = function() { + var anchor = "song" + angularPlayer.getCurrentTrack(); + $scope.menuHidden = !$scope.menuHidden; + if (!$scope.menuHidden) { + $scope.gotoAnchor(anchor); + } + }; + + $scope.playmylist = function(list_id){ + $timeout(function(){ + angularPlayer.clearPlaylist(function(data) { + //add songs to playlist + angularPlayer.addTrackArray($scope.songs); + var index = 0; + if (angularPlayer.getShuffle()) { + var max = $scope.songs.length - 1; + var min = 0; + index = Math.floor(Math.random() * (max - min + 1)) + min; + } + //play first song + angularPlayer.playTrack($scope.songs[index].id); + }); + }, 0); + $scope.setCurrentList(list_id); + }; + + $scope.removemylist = function(list_id){ + var url = '/remove_myplaylist'; + + $http({ + url: url, + method: 'POST', + data: $httpParamSerializerJQLike({ + list_id: list_id, + }), + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }).success(function() { + $rootScope.$broadcast('myplaylist:update'); + $scope.closeWindow(); + Notification.success('删除成功'); + }); + }; + + $scope.clonelist = function(list_id){ + var url = '/clone_playlist'; + + $http({ + url: url, + method: 'POST', + data: $httpParamSerializerJQLike({ + list_id: list_id, + }), + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }).success(function() { + $rootScope.$broadcast('myplaylist:update'); + $scope.closeWindow(); + Notification.success('收藏到我的歌单成功'); + }); + }; + + $scope.myProgress = 0; + $scope.changingProgress = false; + + $rootScope.$on('track:progress', function(event, data) { + if ($scope.changingProgress == false) { + $scope.myProgress = data; + } + }); + + $rootScope.$on('track:myprogress', function(event, data) { + $scope.$apply(function() { + // should use apply to force refresh ui + $scope.myProgress = data; + }); + }); + }]); + + app.controller('InstantSearchController', ['$scope', '$http', '$timeout', 'angularPlayer', 'loWeb', + function($scope, $http, $timeout, angularPlayer, loWeb) { + $scope.tab = 0; + $scope.keywords = ''; + + $scope.changeTab = function(newTab){ + $scope.tab = newTab; + $scope.result = []; + loWeb.get('/search?source='+ $scope.tab + '&keywords=' + $scope.keywords).success(function(data) { + // update the textarea + $scope.result = data.result; + }); + }; + + $scope.isActiveTab = function(tab){ + return $scope.tab === tab; + }; + + $scope.$watch('keywords', function (tmpStr) { + if (!tmpStr || tmpStr.length === 0){ + $scope.result = []; + return 0; + } + // if searchStr is still the same.. + // go ahead and retrieve the data + if (tmpStr === $scope.keywords) + { + loWeb.get('/search?source='+ $scope.tab + '&keywords=' + $scope.keywords).success(function(data) { + // update the textarea + $scope.result = data.result; + }); + } + }); + }]); + + app.directive('errSrc', function() { + // http://stackoverflow.com/questions/16310298/if-a-ngsrc-path-resolves-to-a-404-is-there-a-way-to-fallback-to-a-default + return { + link: function(scope, element, attrs) { + element.bind('error', function() { + if (attrs.src != attrs.errSrc) { + attrs.$set('src', attrs.errSrc); + } + }); + attrs.$observe('ngSrc', function(value) { + if (!value && attrs.errSrc) { + attrs.$set('src', attrs.errSrc); + } + }); + } + } + }); + + app.directive('resize', function ($window) { + return function (scope, element) { + var w = angular.element($window); + var changeHeight = function(){ + var headerHeight = 90; + var footerHeight = 90; + element.css('height', (w.height() - headerHeight - footerHeight) + 'px' ); + }; + w.bind('resize', function () { + changeHeight(); // when window size gets changed + }); + changeHeight(); // when page loads + }; + }); + + app.directive('addAndPlay', ['angularPlayer', function (angularPlayer) { + return { + restrict: "EA", + scope: { + song: "=addAndPlay" + }, + link: function (scope, element, attrs) { + element.bind('click', function (event) { + angularPlayer.addTrack(scope.song); + angularPlayer.playTrack(scope.song.id); + }); + } + }; + }]); + + app.directive('addWithoutPlay', ['angularPlayer', 'Notification', + function (angularPlayer, Notification) { + return { + restrict: "EA", + scope: { + song: "=addWithoutPlay" + }, + link: function (scope, element, attrs) { + element.bind('click', function (event) { + angularPlayer.addTrack(scope.song); + Notification.success("已添加到当前播放歌单"); + }); + } + }; + }]); + + app.directive('openSongSource', ['angularPlayer', '$window', + function (angularPlayer, $window) { + return { + restrict: "EA", + scope: { + song: "=openSongSource" + }, + link: function (scope, element, attrs) { + element.bind('click', function (event) { + $window.open(scope.song.source_url, '_blank'); + }); + } + }; + }]); + + app.directive('draggable', ['angularPlayer', '$document', '$rootScope', + function(angularPlayer, $document, $rootScope) { + return function(scope, element, attr) { + var x; + var container; + + element.on('mousedown', function(event) { + scope.changingProgress = true; + container = document.getElementById('progressbar').getBoundingClientRect(); + // Prevent default dragging of selected content + event.preventDefault(); + x = event.clientX - container.left; + setPosition(); + $document.on('mousemove', mousemove); + $document.on('mouseup', mouseup); + + }); + + function mousemove(event) { + x = event.clientX - container.left; + setPosition(); + } + + function changeProgress(progress) { + if (angularPlayer.getCurrentTrack() === null) { + return; + } + var sound = soundManager.getSoundById(angularPlayer.getCurrentTrack()); + var duration = sound.durationEstimate; + sound.setPosition(progress * duration); + } + + function setPosition() { + if (container) { + if (x < 0) { + x = 0; + } else if (x > container.right - container.left) { + x = container.right - container.left; + } + } + var progress = x / (container.right - container.left); + $rootScope.$broadcast('track:myprogress', progress*100); + } + + function mouseup() { + var progress = x / (container.right - container.left); + changeProgress(progress); + $document.off('mousemove', mousemove); + $document.off('mouseup', mouseup); + scope.changingProgress = false; + } + }; + }]); + + app.controller('MyPlayListController', ['$http','$scope', '$timeout', + 'angularPlayer', function($http, $scope, $timeout, angularPlayer){ + $scope.myplaylists = []; + + $scope.loadMyPlaylist = function(){ + $http.get('/show_myplaylist').success(function(data) { + $scope.myplaylists = data.result; + }); + }; + + $scope.$watch('current_tag', function(newValue, oldValue) { + if (newValue !== oldValue) { + if (newValue == '1') { + $scope.myplaylists = []; + $scope.loadMyPlaylist(); + } + } + }); + $scope.$on('myplaylist:update', function(event, data) { + $scope.loadMyPlaylist(); + }); + + }]); + + app.controller('PlayListController', ['$http','$scope', '$timeout', + 'angularPlayer','loWeb', function($http, $scope, $timeout, angularPlayer, loWeb){ + $scope.result = []; + + $scope.tab = 0; + + $scope.changeTab = function(newTab){ + $scope.tab = newTab; + $scope.result = []; + + loWeb.get('/show_playlist?source=' + $scope.tab).success(function(data) { + $scope.result = data.result; + }); + + // $http.get('/show_playlist?source=' + $scope.tab).success(function(data) { + // $scope.result = data.result; + // }); + }; + + $scope.isActiveTab = function(tab){ + return $scope.tab === tab; + }; + + + $scope.loadPlaylist = function(){ + loWeb.get('/show_playlist?source=' + $scope.tab).success(function(data) { + $scope.result = data.result; + }); + }; + }]); + + // 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("红心兆赫已导入我的歌单"); + // } + // }); + // } + // }]); + +})(); \ No newline at end of file diff --git a/js/background.js b/js/background.js new file mode 100644 index 0000000..0caa60f --- /dev/null +++ b/js/background.js @@ -0,0 +1,47 @@ +chrome.browserAction.onClicked.addListener(function(tab) { + chrome.tabs.create({'url': chrome.extension.getURL('listen1.html')}, function(tab) { + // Tab opened. + }); +}); + + +function hack_referer_header(details) { + var referer_value = ''; + if (details.url.indexOf("://music.163.com/") != -1) { + referer_value = "http://music.163.com/"; + } + + if (details.url.indexOf(".xiami.com/") != -1) { + referer_value = "http://m.xiami.com/"; + } + + if (details.url.indexOf(".qq.com/") != -1) { + referer_value = "http://y.qq.com/"; + } + + var isRefererSet = false; + var headers = details.requestHeaders, + blockingResponse = {}; + + for (var i = 0, l = headers.length; i < l; ++i) { + if (headers[i].name == 'Referer') { + headers[i].value = referer_value; + isRefererSet = true; + break; + } + } + + if (!isRefererSet) { + headers.push({ + name: "Referer", + value: referer_value + }); + } + + blockingResponse.requestHeaders = headers; + return blockingResponse; +}; + +chrome.webRequest.onBeforeSendHeaders.addListener(hack_referer_header, { + urls: ["*://music.163.com/*", "*://*.xiami.com/*", "*://*.qq.com/*"] +}, ['requestHeaders', 'blocking']); \ No newline at end of file diff --git a/js/bigint.js b/js/bigint.js new file mode 100644 index 0000000..7535b37 --- /dev/null +++ b/js/bigint.js @@ -0,0 +1,1507 @@ +//////////////////////////////////////////////////////////////////////////////////////// +// Big Integer Library v. 5.5 +// Created 2000, last modified 2013 +// Leemon Baird +// www.leemon.com +// +// Version history: +// v 5.5 17 Mar 2013 +// - two lines of a form like "if (x<0) x+=n" had the "if" changed to "while" to +// handle the case when x<-n. (Thanks to James Ansell for finding that bug) +// v 5.4 3 Oct 2009 +// - added "var i" to greaterShift() so i is not global. (Thanks to P巘er Szab� for finding that bug) +// +// v 5.3 21 Sep 2009 +// - added randProbPrime(k) for probable primes +// - unrolled loop in mont_ (slightly faster) +// - millerRabin now takes a bigInt parameter rather than an int +// +// v 5.2 15 Sep 2009 +// - fixed capitalization in call to int2bigInt in randBigInt +// (thanks to Emili Evripidou, Reinhold Behringer, and Samuel Macaleese for finding that bug) +// +// v 5.1 8 Oct 2007 +// - renamed inverseModInt_ to inverseModInt since it doesn't change its parameters +// - added functions GCD and randBigInt, which call GCD_ and randBigInt_ +// - fixed a bug found by Rob Visser (see comment with his name below) +// - improved comments +// +// This file is public domain. You can use it for any purpose without restriction. +// I do not guarantee that it is correct, so use it at your own risk. If you use +// it for something interesting, I'd appreciate hearing about it. If you find +// any bugs or make any improvements, I'd appreciate hearing about those too. +// It would also be nice if my name and URL were left in the comments. But none +// of that is required. +// +// This code defines a bigInt library for arbitrary-precision integers. +// A bigInt is an array of integers storing the value in chunks of bpe bits, +// little endian (buff[0] is the least significant word). +// Negative bigInts are stored two's complement. Almost all the functions treat +// bigInts as nonnegative. The few that view them as two's complement say so +// in their comments. Some functions assume their parameters have at least one +// leading zero element. Functions with an underscore at the end of the name put +// their answer into one of the arrays passed in, and have unpredictable behavior +// in case of overflow, so the caller must make sure the arrays are big enough to +// hold the answer. But the average user should never have to call any of the +// underscored functions. Each important underscored function has a wrapper function +// of the same name without the underscore that takes care of the details for you. +// For each underscored function where a parameter is modified, that same variable +// must not be used as another argument too. So, you cannot square x by doing +// multMod_(x,x,n). You must use squareMod_(x,n) instead, or do y=dup(x); multMod_(x,y,n). +// Or simply use the multMod(x,x,n) function without the underscore, where +// such issues never arise, because non-underscored functions never change +// their parameters; they always allocate new memory for the answer that is returned. +// +// These functions are designed to avoid frequent dynamic memory allocation in the inner loop. +// For most functions, if it needs a BigInt as a local variable it will actually use +// a global, and will only allocate to it only when it's not the right size. This ensures +// that when a function is called repeatedly with same-sized parameters, it only allocates +// memory on the first call. +// +// Note that for cryptographic purposes, the calls to Math.random() must +// be replaced with calls to a better pseudorandom number generator. +// +// In the following, "bigInt" means a bigInt with at least one leading zero element, +// and "integer" means a nonnegative integer less than radix. In some cases, integer +// can be negative. Negative bigInts are 2s complement. +// +// The following functions do not modify their inputs. +// Those returning a bigInt, string, or Array will dynamically allocate memory for that value. +// Those returning a boolean will return the integer 0 (false) or 1 (true). +// Those returning boolean or int will not allocate memory except possibly on the first +// time they're called with a given parameter size. +// +// bigInt add(x,y) //return (x+y) for bigInts x and y. +// bigInt addInt(x,n) //return (x+n) where x is a bigInt and n is an integer. +// string bigInt2str(x,base) //return a string form of bigInt x in a given base, with 2 <= base <= 95 +// int bitSize(x) //return how many bits long the bigInt x is, not counting leading zeros +// bigInt dup(x) //return a copy of bigInt x +// boolean equals(x,y) //is the bigInt x equal to the bigint y? +// boolean equalsInt(x,y) //is bigint x equal to integer y? +// bigInt expand(x,n) //return a copy of x with at least n elements, adding leading zeros if needed +// Array findPrimes(n) //return array of all primes less than integer n +// bigInt GCD(x,y) //return greatest common divisor of bigInts x and y (each with same number of elements). +// boolean greater(x,y) //is x>y? (x and y are nonnegative bigInts) +// boolean greaterShift(x,y,shift)//is (x <<(shift*bpe)) > y? +// bigInt int2bigInt(t,n,m) //return a bigInt equal to integer t, with at least n bits and m array elements +// bigInt inverseMod(x,n) //return (x**(-1) mod n) for bigInts x and n. If no inverse exists, it returns null +// int inverseModInt(x,n) //return x**(-1) mod n, for integers x and n. Return 0 if there is no inverse +// boolean isZero(x) //is the bigInt x equal to zero? +// boolean millerRabin(x,b) //does one round of Miller-Rabin base integer b say that bigInt x is possibly prime? (b is bigInt, 1=1). If s=1, then the most significant of those n bits is set to 1. +// bigInt randTruePrime(k) //return a new, random, k-bit, true prime bigInt using Maurer's algorithm. +// bigInt randProbPrime(k) //return a new, random, k-bit, probable prime bigInt (probability it's composite less than 2^-80). +// bigInt str2bigInt(s,b,n,m) //return a bigInt for number represented in string s in base b with at least n bits and m array elements +// bigInt sub(x,y) //return (x-y) for bigInts x and y. Negative answers will be 2s complement +// bigInt trim(x,k) //return a copy of x with exactly k leading zero elements +// +// +// The following functions each have a non-underscored version, which most users should call instead. +// These functions each write to a single parameter, and the caller is responsible for ensuring the array +// passed in is large enough to hold the result. +// +// void addInt_(x,n) //do x=x+n where x is a bigInt and n is an integer +// void add_(x,y) //do x=x+y for bigInts x and y +// void copy_(x,y) //do x=y on bigInts x and y +// void copyInt_(x,n) //do x=n on bigInt x and integer n +// void GCD_(x,y) //set x to the greatest common divisor of bigInts x and y, (y is destroyed). (This never overflows its array). +// boolean inverseMod_(x,n) //do x=x**(-1) mod n, for bigInts x and n. Returns 1 (0) if inverse does (doesn't) exist +// void mod_(x,n) //do x=x mod n for bigInts x and n. (This never overflows its array). +// void mult_(x,y) //do x=x*y for bigInts x and y. +// void multMod_(x,y,n) //do x=x*y mod n for bigInts x,y,n. +// void powMod_(x,y,n) //do x=x**y mod n, where x,y,n are bigInts (n is odd) and ** is exponentiation. 0**0=1. +// void randBigInt_(b,n,s) //do b = an n-bit random BigInt. if s=1, then nth bit (most significant bit) is set to 1. n>=1. +// void randTruePrime_(ans,k) //do ans = a random k-bit true random prime (not just probable prime) with 1 in the msb. +// void sub_(x,y) //do x=x-y for bigInts x and y. Negative answers will be 2s complement. +// +// The following functions do NOT have a non-underscored version. +// They each write a bigInt result to one or more parameters. The caller is responsible for +// ensuring the arrays passed in are large enough to hold the results. +// +// void addShift_(x,y,ys) //do x=x+(y<<(ys*bpe)) +// void carry_(x) //do carries and borrows so each element of the bigInt x fits in bpe bits. +// void divide_(x,y,q,r) //divide x by y giving quotient q and remainder r +// int divInt_(x,n) //do x=floor(x/n) for bigInt x and integer n, and return the remainder. (This never overflows its array). +// int eGCD_(x,y,d,a,b) //sets a,b,d to positive bigInts such that d = GCD_(x,y) = a*x-b*y +// void halve_(x) //do x=floor(|x|/2)*sgn(x) for bigInt x in 2's complement. (This never overflows its array). +// void leftShift_(x,n) //left shift bigInt x by n bits. n64 multiplier, but not with JavaScript's 32*32->32) +// - speeding up mont_(x,y,n,np) when x==y by doing a non-modular, non-Montgomery square +// followed by a Montgomery reduction. The intermediate answer will be twice as long as x, so that +// method would be slower. This is unfortunate because the code currently spends almost all of its time +// doing mont_(x,x,...), both for randTruePrime_() and powMod_(). A faster method for Montgomery squaring +// would have a large impact on the speed of randTruePrime_() and powMod_(). HAC has a couple of poorly-worded +// sentences that seem to imply it's faster to do a non-modular square followed by a single +// Montgomery reduction, but that's obviously wrong. +//////////////////////////////////////////////////////////////////////////////////////// + +//globals +bpe=0; //bits stored per array element +mask=0; //AND this with an array element to chop it down to bpe bits +radix=mask+1; //equals 2^bpe. A single 1 bit to the left of the last bit of mask. + +//the digits for converting to different bases +digitsStr='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_=!@#$%^&*()[]{}|;:,.<>/?`~ \\\'\"+-'; + +//initialize the global variables +for (bpe=0; (1<<(bpe+1)) > (1<>=1; //bpe=number of bits in one element of the array representing the bigInt +mask=(1<0); j--); + for (z=0,w=x[j]; w; (w>>=1),z++); + z+=bpe*j; + return z; +} + +//return a copy of x with at least n elements, adding leading zeros if needed +function expand(x,n) { + var ans=int2bigInt(0,(x.length>n ? x.length : n)*bpe,0); + copy_(ans,x); + return ans; +} + +//return a k-bit true random prime using Maurer's algorithm. +function randTruePrime(k) { + var ans=int2bigInt(0,k,0); + randTruePrime_(ans,k); + return trim(ans,1); +} + +//return a k-bit random probable prime with probability of error < 2^-80 +function randProbPrime(k) { + if (k>=600) return randProbPrimeRounds(k,2); //numbers from HAC table 4.3 + if (k>=550) return randProbPrimeRounds(k,4); + if (k>=500) return randProbPrimeRounds(k,5); + if (k>=400) return randProbPrimeRounds(k,6); + if (k>=350) return randProbPrimeRounds(k,7); + if (k>=300) return randProbPrimeRounds(k,9); + if (k>=250) return randProbPrimeRounds(k,12); //numbers from HAC table 4.4 + if (k>=200) return randProbPrimeRounds(k,15); + if (k>=150) return randProbPrimeRounds(k,18); + if (k>=100) return randProbPrimeRounds(k,27); + return randProbPrimeRounds(k,40); //number from HAC remark 4.26 (only an estimate) +} + +//return a k-bit probable random prime using n rounds of Miller Rabin (after trial division with small primes) +function randProbPrimeRounds(k,n) { + var ans, i, divisible, B; + B=30000; //B is largest prime to use in trial division + ans=int2bigInt(0,k,0); + + //optimization: try larger and smaller B to find the best limit. + + if (primes.length==0) + primes=findPrimes(30000); //check for divisibility by primes <=30000 + + if (rpprb.length!=ans.length) + rpprb=dup(ans); + + for (;;) { //keep trying random values for ans until one appears to be prime + //optimization: pick a random number times L=2*3*5*...*p, plus a + // random element of the list of all numbers in [0,L) not divisible by any prime up to p. + // This can reduce the amount of random number generation. + + randBigInt_(ans,k,0); //ans = a random odd number to check + ans[0] |= 1; + divisible=0; + + //check ans for divisibility by small primes up to B + for (i=0; (iy.length ? x.length+1 : y.length+1)); + sub_(ans,y); + return trim(ans,1); +} + +//return (x+y) for bigInts x and y. +function add(x,y) { + var ans=expand(x,(x.length>y.length ? x.length+1 : y.length+1)); + add_(ans,y); + return trim(ans,1); +} + +//return (x**(-1) mod n) for bigInts x and n. If no inverse exists, it returns null +function inverseMod(x,n) { + var ans=expand(x,n.length); + var s; + s=inverseMod_(ans,n); + return s ? trim(ans,1) : null; +} + +//return (x*y mod n) for bigInts x,y,n. For greater speed, let y= 2 + + if (s_i2.length!=ans.length) { + s_i2=dup(ans); + s_R =dup(ans); + s_n1=dup(ans); + s_r2=dup(ans); + s_d =dup(ans); + s_x1=dup(ans); + s_x2=dup(ans); + s_b =dup(ans); + s_n =dup(ans); + s_i =dup(ans); + s_rm=dup(ans); + s_q =dup(ans); + s_a =dup(ans); + s_aa=dup(ans); + } + + if (k <= recLimit) { //generate small random primes by trial division up to its square root + pm=(1<<((k+2)>>1))-1; //pm is binary number with all ones, just over sqrt(2^k) + copyInt_(ans,0); + for (dd=1;dd;) { + dd=0; + ans[0]= 1 | (1<<(k-1)) | Math.floor(Math.random()*(1<2*m) //generate this k-bit number by first recursively generating a number that has between k/2 and k-m bits + for (r=1; k-k*r<=m; ) + r=pows[Math.floor(Math.random()*512)]; //r=Math.pow(2,Math.random()-1); + else + r=.5; + + //simulation suggests the more complex algorithm using r=.333 is only slightly faster. + + recSize=Math.floor(r*k)+1; + + randTruePrime_(s_q,recSize); + copyInt_(s_i2,0); + s_i2[Math.floor((k-2)/bpe)] |= (1<<((k-2)%bpe)); //s_i2=2^(k-2) + divide_(s_i2,s_q,s_i,s_rm); //s_i=floor((2^(k-1))/(2q)) + + z=bitSize(s_i); + + for (;;) { + for (;;) { //generate z-bit numbers until one falls in the range [0,s_i-1] + randBigInt_(s_R,z,0); + if (greater(s_i,s_R)) + break; + } //now s_R is in the range [0,s_i-1] + addInt_(s_R,1); //now s_R is in the range [1,s_i] + add_(s_R,s_i); //now s_R is in the range [s_i+1,2*s_i] + + copy_(s_n,s_q); + mult_(s_n,s_R); + multInt_(s_n,2); + addInt_(s_n,1); //s_n=2*s_R*s_q+1 + + copy_(s_r2,s_R); + multInt_(s_r2,2); //s_r2=2*s_R + + //check s_n for divisibility by small primes up to B + for (divisible=0,j=0; (j0); j--); //strip leading zeros + for (zz=0,w=s_n[j]; w; (w>>=1),zz++); + zz+=bpe*j; //zz=number of bits in s_n, ignoring leading zeros + for (;;) { //generate z-bit numbers until one falls in the range [0,s_n-1] + randBigInt_(s_a,zz,0); + if (greater(s_n,s_a)) + break; + } //now s_a is in the range [0,s_n-1] + addInt_(s_n,3); //now s_a is in the range [0,s_n-4] + addInt_(s_a,2); //now s_a is in the range [2,s_n-2] + copy_(s_b,s_a); + copy_(s_n1,s_n); + addInt_(s_n1,-1); + powMod_(s_b,s_n1,s_n); //s_b=s_a^(s_n-1) modulo s_n + addInt_(s_b,-1); + if (isZero(s_b)) { + copy_(s_b,s_a); + powMod_(s_b,s_r2,s_n); + addInt_(s_b,-1); + copy_(s_aa,s_n); + copy_(s_d,s_b); + GCD_(s_d,s_n); //if s_b and s_n are relatively prime, then s_n is a prime + if (equalsInt(s_d,1)) { + copy_(ans,s_aa); + return; //if we've made it this far, then s_n is absolutely guaranteed to be prime + } + } + } + } +} + +//Return an n-bit random BigInt (n>=1). If s=1, then the most significant of those n bits is set to 1. +function randBigInt(n,s) { + var a,b; + a=Math.floor((n-1)/bpe)+2; //# array elements to hold the BigInt with a leading 0 element + b=int2bigInt(0,0,a); + randBigInt_(b,n,s); + return b; +} + +//Set b to an n-bit random BigInt. If s=1, then the most significant of those n bits is set to 1. +//Array b must be big enough to hold the result. Must have n>=1 +function randBigInt_(b,n,s) { + var i,a; + for (i=0;i=0;i--); //find most significant element of x + xp=x[i]; + yp=y[i]; + A=1; B=0; C=0; D=1; + while ((yp+C) && (yp+D)) { + q =Math.floor((xp+A)/(yp+C)); + qp=Math.floor((xp+B)/(yp+D)); + if (q!=qp) + break; + t= A-q*C; A=C; C=t; // do (A,B,xp, C,D,yp) = (C,D,yp, A,B,xp) - q*(0,0,0, C,D,yp) + t= B-q*D; B=D; D=t; + t=xp-q*yp; xp=yp; yp=t; + } + if (B) { + copy_(T,x); + linComb_(x,y,A,B); //x=A*x+B*y + linComb_(y,T,D,C); //y=D*y+C*T + } else { + mod_(x,y); + copy_(T,x); + copy_(x,y); + copy_(y,T); + } + } + if (y[0]==0) + return; + t=modInt(x,y[0]); + copyInt_(x,y[0]); + y[0]=t; + while (y[0]) { + x[0]%=y[0]; + t=x[0]; x[0]=y[0]; y[0]=t; + } +} + +//do x=x**(-1) mod n, for bigInts x and n. +//If no inverse exists, it sets x to zero and returns 0, else it returns 1. +//The x array must be at least as large as the n array. +function inverseMod_(x,n) { + var k=1+2*Math.max(x.length,n.length); + + if(!(x[0]&1) && !(n[0]&1)) { //if both inputs are even, then inverse doesn't exist + copyInt_(x,0); + return 0; + } + + if (eg_u.length!=k) { + eg_u=new Array(k); + eg_v=new Array(k); + eg_A=new Array(k); + eg_B=new Array(k); + eg_C=new Array(k); + eg_D=new Array(k); + } + + copy_(eg_u,x); + copy_(eg_v,n); + copyInt_(eg_A,1); + copyInt_(eg_B,0); + copyInt_(eg_C,0); + copyInt_(eg_D,1); + for (;;) { + while(!(eg_u[0]&1)) { //while eg_u is even + halve_(eg_u); + if (!(eg_A[0]&1) && !(eg_B[0]&1)) { //if eg_A==eg_B==0 mod 2 + halve_(eg_A); + halve_(eg_B); + } else { + add_(eg_A,n); halve_(eg_A); + sub_(eg_B,x); halve_(eg_B); + } + } + + while (!(eg_v[0]&1)) { //while eg_v is even + halve_(eg_v); + if (!(eg_C[0]&1) && !(eg_D[0]&1)) { //if eg_C==eg_D==0 mod 2 + halve_(eg_C); + halve_(eg_D); + } else { + add_(eg_C,n); halve_(eg_C); + sub_(eg_D,x); halve_(eg_D); + } + } + + if (!greater(eg_v,eg_u)) { //eg_v <= eg_u + sub_(eg_u,eg_v); + sub_(eg_A,eg_C); + sub_(eg_B,eg_D); + } else { //eg_v > eg_u + sub_(eg_v,eg_u); + sub_(eg_C,eg_A); + sub_(eg_D,eg_B); + } + + if (equalsInt(eg_u,0)) { + while (negative(eg_C)) //make sure answer is nonnegative + add_(eg_C,n); + copy_(x,eg_C); + + if (!equalsInt(eg_v,1)) { //if GCD_(x,n)!=1, then there is no inverse + copyInt_(x,0); + return 0; + } + return 1; + } + } +} + +//return x**(-1) mod n, for integers x and n. Return 0 if there is no inverse +function inverseModInt(x,n) { + var a=1,b=0,t; + for (;;) { + if (x==1) return a; + if (x==0) return 0; + b-=a*Math.floor(n/x); + n%=x; + + if (n==1) return b; //to avoid negatives, change this b to n-b, and each -= to += + if (n==0) return 0; + a-=b*Math.floor(x/n); + x%=n; + } +} + +//this deprecated function is for backward compatibility only. +function inverseModInt_(x,n) { + return inverseModInt(x,n); +} + + +//Given positive bigInts x and y, change the bigints v, a, and b to positive bigInts such that: +// v = GCD_(x,y) = a*x-b*y +//The bigInts v, a, b, must have exactly as many elements as the larger of x and y. +function eGCD_(x,y,v,a,b) { + var g=0; + var k=Math.max(x.length,y.length); + if (eg_u.length!=k) { + eg_u=new Array(k); + eg_A=new Array(k); + eg_B=new Array(k); + eg_C=new Array(k); + eg_D=new Array(k); + } + while(!(x[0]&1) && !(y[0]&1)) { //while x and y both even + halve_(x); + halve_(y); + g++; + } + copy_(eg_u,x); + copy_(v,y); + copyInt_(eg_A,1); + copyInt_(eg_B,0); + copyInt_(eg_C,0); + copyInt_(eg_D,1); + for (;;) { + while(!(eg_u[0]&1)) { //while u is even + halve_(eg_u); + if (!(eg_A[0]&1) && !(eg_B[0]&1)) { //if A==B==0 mod 2 + halve_(eg_A); + halve_(eg_B); + } else { + add_(eg_A,y); halve_(eg_A); + sub_(eg_B,x); halve_(eg_B); + } + } + + while (!(v[0]&1)) { //while v is even + halve_(v); + if (!(eg_C[0]&1) && !(eg_D[0]&1)) { //if C==D==0 mod 2 + halve_(eg_C); + halve_(eg_D); + } else { + add_(eg_C,y); halve_(eg_C); + sub_(eg_D,x); halve_(eg_D); + } + } + + if (!greater(v,eg_u)) { //v<=u + sub_(eg_u,v); + sub_(eg_A,eg_C); + sub_(eg_B,eg_D); + } else { //v>u + sub_(v,eg_u); + sub_(eg_C,eg_A); + sub_(eg_D,eg_B); + } + if (equalsInt(eg_u,0)) { + while (negative(eg_C)) { //make sure a (C) is nonnegative + add_(eg_C,y); + sub_(eg_D,x); + } + multInt_(eg_D,-1); ///make sure b (D) is nonnegative + copy_(a,eg_C); + copy_(b,eg_D); + leftShift_(v,g); + return; + } + } +} + + +//is bigInt x negative? +function negative(x) { + return ((x[x.length-1]>>(bpe-1))&1); +} + + +//is (x << (shift*bpe)) > y? +//x and y are nonnegative bigInts +//shift is a nonnegative integer +function greaterShift(x,y,shift) { + var i, kx=x.length, ky=y.length; + k=((kx+shift)=0; i++) + if (x[i]>0) + return 1; //if there are nonzeros in x to the left of the first column of y, then x is bigger + for (i=kx-1+shift; i0) + return 0; //if there are nonzeros in y to the left of the first column of x, then x is not bigger + for (i=k-1; i>=shift; i--) + if (x[i-shift]>y[i]) return 1; + else if (x[i-shift] y? (x and y both nonnegative) +function greater(x,y) { + var i; + var k=(x.length=0;i--) + if (x[i]>y[i]) + return 1; + else if (x[i]= y.length >= 2. +function divide_(x,y,q,r) { + var kx, ky; + var i,j,y1,y2,c,a,b; + copy_(r,x); + for (ky=y.length;y[ky-1]==0;ky--); //ky is number of elements in y, not including leading zeros + + //normalize: ensure the most significant element of y has its highest bit set + b=y[ky-1]; + for (a=0; b; a++) + b>>=1; + a=bpe-a; //a is how many bits to shift so that the high order bit of y is leftmost in its array element + leftShift_(y,a); //multiply both by 1<ky;kx--); //kx is number of elements in normalized x, not including leading zeros + + copyInt_(q,0); // q=0 + while (!greaterShift(y,r,kx-ky)) { // while (leftShift_(y,kx-ky) <= r) { + subShift_(r,y,kx-ky); // r=r-leftShift_(y,kx-ky) + q[kx-ky]++; // q[kx-ky]++; + } // } + + for (i=kx-1; i>=ky; i--) { + if (r[i]==y[ky-1]) + q[i-ky]=mask; + else + q[i-ky]=Math.floor((r[i]*radix+r[i-1])/y[ky-1]); + + //The following for(;;) loop is equivalent to the commented while loop, + //except that the uncommented version avoids overflow. + //The commented loop comes from HAC, which assumes r[-1]==y[-1]==0 + // while (q[i-ky]*(y[ky-1]*radix+y[ky-2]) > r[i]*radix*radix+r[i-1]*radix+r[i-2]) + // q[i-ky]--; + for (;;) { + y2=(ky>1 ? y[ky-2] : 0)*q[i-ky]; + c=y2>>bpe; + y2=y2 & mask; + y1=c+q[i-ky]*y[ky-1]; + c=y1>>bpe; + y1=y1 & mask; + + if (c==r[i] ? y1==r[i-1] ? y2>(i>1 ? r[i-2] : 0) : y1>r[i-1] : c>r[i]) + q[i-ky]--; + else + break; + } + + linCombShift_(r,y,-q[i-ky],i-ky); //r=r-q[i-ky]*leftShift_(y,i-ky) + if (negative(r)) { + addShift_(r,y,i-ky); //r=r+leftShift_(y,i-ky) + q[i-ky]--; + } + } + + rightShift_(y,a); //undo the normalization step + rightShift_(r,a); //undo the normalization step +} + +//do carries and borrows so each element of the bigInt x fits in bpe bits. +function carry_(x) { + var i,k,c,b; + k=x.length; + c=0; + for (i=0;i>bpe); + c+=b*radix; + } + x[i]=c & mask; + c=(c>>bpe)-b; + } +} + +//return x mod n for bigInt x and integer n. +function modInt(x,n) { + var i,c=0; + for (i=x.length-1; i>=0; i--) + c=(c*radix+x[i])%n; + return c; +} + +//convert the integer t into a bigInt with at least the given number of bits. +//the returned array stores the bigInt in bpe-bit chunks, little endian (buff[0] is least significant word) +//Pad the array with leading zeros so that it has at least minSize elements. +//There will always be at least one leading 0 element. +function int2bigInt(t,bits,minSize) { + var i,k; + k=Math.ceil(bits/bpe)+1; + k=minSize>k ? minSize : k; + buff=new Array(k); + copyInt_(buff,t); + return buff; +} + +//return the bigInt given a string representation in a given base. +//Pad the array with leading zeros so that it has at least minSize elements. +//If base=-1, then it reads in a space-separated list of array elements in decimal. +//The array will always have at least one leading zero, unless base=-1. +function str2bigInt(s,base,minSize) { + var d, i, j, x, y, kk; + var k=s.length; + if (base==-1) { //comma-separated list of array elements in decimal + x=new Array(0); + for (;;) { + y=new Array(x.length+1); + for (i=0;i=36) //convert lowercase to uppercase if base<=36 + d-=26; + if (d>=base || d<0) { //stop at first illegal character + break; + } + multInt_(x,base); + addInt_(x,d); + } + + for (k=x.length;k>0 && !x[k-1];k--); //strip off leading zeros + k=minSize>k+1 ? minSize : k+1; + y=new Array(k); + kk=ky.length) { + for (;i0;i--) + s+=x[i]+','; + s+=x[0]; + } + else { //return it in the given base + while (!isZero(s6)) { + t=divInt_(s6,base); //t=s6 % base; s6=floor(s6/base); + s=digitsStr.substring(t,t+1)+s; + } + } + if (s.length==0) + s="0"; + return s; +} + +//returns a duplicate of bigInt x +function dup(x) { + var i; + buff=new Array(x.length); + copy_(buff,x); + return buff; +} + +//do x=y on bigInts x and y. x must be an array at least as big as y (not counting the leading zeros in y). +function copy_(x,y) { + var i; + var k=x.length>=bpe; + } +} + +//do x=x+n where x is a bigInt and n is an integer. +//x must be large enough to hold the result. +function addInt_(x,n) { + var i,k,c,b; + x[0]+=n; + k=x.length; + c=0; + for (i=0;i>bpe); + c+=b*radix; + } + x[i]=c & mask; + c=(c>>bpe)-b; + if (!c) return; //stop carrying as soon as the carry is zero + } +} + +//right shift bigInt x by n bits. 0 <= n < bpe. +function rightShift_(x,n) { + var i; + var k=Math.floor(n/bpe); + if (k) { + for (i=0;i>n)); + } + x[i]>>=n; +} + +//do x=floor(|x|/2)*sgn(x) for bigInt x in 2's complement +function halve_(x) { + var i; + for (i=0;i>1)); + } + x[i]=(x[i]>>1) | (x[i] & (radix>>1)); //most significant bit stays the same +} + +//left shift bigInt x by n bits. +function leftShift_(x,n) { + var i; + var k=Math.floor(n/bpe); + if (k) { + for (i=x.length; i>=k; i--) //left shift x by k elements + x[i]=x[i-k]; + for (;i>=0;i--) + x[i]=0; + n%=bpe; + } + if (!n) + return; + for (i=x.length-1;i>0;i--) { + x[i]=mask & ((x[i]<>(bpe-n))); + } + x[i]=mask & (x[i]<>bpe); + c+=b*radix; + } + x[i]=c & mask; + c=(c>>bpe)-b; + } +} + +//do x=floor(x/n) for bigInt x and integer n, and return the remainder +function divInt_(x,n) { + var i,r=0,s; + for (i=x.length-1;i>=0;i--) { + s=r*radix+x[i]; + x[i]=Math.floor(s/n); + r=s%n; + } + return r; +} + +//do the linear combination x=a*x+b*y for bigInts x and y, and integers a and b. +//x must be large enough to hold the answer. +function linComb_(x,y,a,b) { + var i,c,k,kk; + k=x.length>=bpe; + } + for (i=k;i>=bpe; + } +} + +//do the linear combination x=a*x+b*(y<<(ys*bpe)) for bigInts x and y, and integers a, b and ys. +//x must be large enough to hold the answer. +function linCombShift_(x,y,b,ys) { + var i,c,k,kk; + k=x.length>=bpe; + } + for (i=k;c && i>=bpe; + } +} + +//do x=x+(y<<(ys*bpe)) for bigInts x and y, and integers a,b and ys. +//x must be large enough to hold the answer. +function addShift_(x,y,ys) { + var i,c,k,kk; + k=x.length>=bpe; + } + for (i=k;c && i>=bpe; + } +} + +//do x=x-(y<<(ys*bpe)) for bigInts x and y, and integers a,b and ys. +//x must be large enough to hold the answer. +function subShift_(x,y,ys) { + var i,c,k,kk; + k=x.length>=bpe; + } + for (i=k;c && i>=bpe; + } +} + +//do x=x-y for bigInts x and y. +//x must be large enough to hold the answer. +//negative answers will be 2s complement +function sub_(x,y) { + var i,c,k,kk; + k=x.length>=bpe; + } + for (i=k;c && i>=bpe; + } +} + +//do x=x+y for bigInts x and y. +//x must be large enough to hold the answer. +function add_(x,y) { + var i,c,k,kk; + k=x.length>=bpe; + } + for (i=k;c && i>=bpe; + } +} + +//do x=x*y for bigInts x and y. This is faster when y0 && !x[kx-1]; kx--); //ignore leading zeros in x + k=kx>n.length ? 2*kx : 2*n.length; //k=# elements in the product, which is twice the elements in the larger of x and n + if (s0.length!=k) + s0=new Array(k); + copyInt_(s0,0); + for (i=0;i>=bpe; + for (j=i+1;j>=bpe; + } + s0[i+kx]=c; + } + mod_(s0,n); + copy_(x,s0); +} + +//return x with exactly k leading zero elements +function trim(x,k) { + var i,y; + for (i=x.length; i>0 && !x[i-1]; i--); + y=new Array(i+k); + copy_(y,x); + return y; +} + +//do x=x**y mod n, where x,y,n are bigInts and ** is exponentiation. 0**0=1. +//this is faster when n is odd. x usually needs to have as many elements as n. +function powMod_(x,y,n) { + var k1,k2,kn,np; + if(s7.length!=n.length) + s7=dup(n); + + //for even modulus, use a simple square-and-multiply algorithm, + //rather than using the more complex Montgomery algorithm. + if ((n[0]&1)==0) { + copy_(s7,x); + copyInt_(x,1); + while(!equalsInt(y,0)) { + if (y[0]&1) + multMod_(x,s7,n); + divInt_(y,2); + squareMod_(s7,n); + } + return; + } + + //calculate np from n for the Montgomery multiplications + copyInt_(s7,0); + for (kn=n.length;kn>0 && !n[kn-1];kn--); + np=radix-inverseModInt(modInt(n,radix),radix); + s7[kn]=1; + multMod_(x ,s7,n); // x = x * 2**(kn*bp) mod n + + if (s3.length!=x.length) + s3=dup(x); + else + copy_(s3,x); + + for (k1=y.length-1;k1>0 & !y[k1]; k1--); //k1=first nonzero element of y + if (y[k1]==0) { //anything to the 0th power is 1 + copyInt_(x,1); + return; + } + for (k2=1<<(bpe-1);k2 && !(y[k1] & k2); k2>>=1); //k2=position of first 1 bit in y[k1] + for (;;) { + if (!(k2>>=1)) { //look at next bit of y + k1--; + if (k1<0) { + mont_(x,one,n,np); + return; + } + k2=1<<(bpe-1); + } + mont_(x,x,n,np); + + if (k2 & y[k1]) //if next bit is a 1 + mont_(x,s3,n,np); + } +} + + +//do x=x*y*Ri mod n for bigInts x,y,n, +// where Ri = 2**(-kn*bpe) mod n, and kn is the +// number of elements in the n array, not +// counting leading zeros. +//x array must have at least as many elemnts as the n array +//It's OK if x and y are the same variable. +//must have: +// x,y < n +// n is odd +// np = -(n^(-1)) mod radix +function mont_(x,y,n,np) { + var i,j,c,ui,t,ks; + var kn=n.length; + var ky=y.length; + + if (sa.length!=kn) + sa=new Array(kn); + + copyInt_(sa,0); + + for (;kn>0 && n[kn-1]==0;kn--); //ignore leading zeros of n + for (;ky>0 && y[ky-1]==0;ky--); //ignore leading zeros of y + ks=sa.length-1; //sa will never have more than this many nonzero elements. + + //the following loop consumes 95% of the runtime for randTruePrime_() and powMod_() for large numbers + for (i=0; i> bpe; + t=x[i]; + + //do sa=(sa+x[i]*y+ui*n)/b where b=2**bpe. Loop is unrolled 5-fold for speed + j=1; + for (;j>=bpe; j++; + c+=sa[j]+ui*n[j]+t*y[j]; sa[j-1]=c & mask; c>>=bpe; j++; + c+=sa[j]+ui*n[j]+t*y[j]; sa[j-1]=c & mask; c>>=bpe; j++; + c+=sa[j]+ui*n[j]+t*y[j]; sa[j-1]=c & mask; c>>=bpe; j++; + c+=sa[j]+ui*n[j]+t*y[j]; sa[j-1]=c & mask; c>>=bpe; j++; } + for (;j>=bpe; j++; } + for (;j>=bpe; j++; + c+=sa[j]+ui*n[j]; sa[j-1]=c & mask; c>>=bpe; j++; + c+=sa[j]+ui*n[j]; sa[j-1]=c & mask; c>>=bpe; j++; + c+=sa[j]+ui*n[j]; sa[j-1]=c & mask; c>>=bpe; j++; + c+=sa[j]+ui*n[j]; sa[j-1]=c & mask; c>>=bpe; j++; } + for (;j>=bpe; j++; } + for (;j>=bpe; j++; } + sa[j-1]=c & mask; + } + + if (!greater(n,sa)) + sub_(sa,n); + copy_(x,sa); +} + diff --git a/js/loweb.js b/js/loweb.js new file mode 100644 index 0000000..1aed4dc --- /dev/null +++ b/js/loweb.js @@ -0,0 +1,90 @@ +var ngloWebManager = angular.module('loWebManager', []); + +ngloWebManager.factory('loWeb', ['$rootScope', '$log', '$http', '$httpParamSerializerJQLike', +function($rootScope, $log, $http, $httpParamSerializerJQLike) { + var response = null; + return { + foo: function(){ + console.log('foo'); + }, + get: function(url) { + if (url.search('/show_playlist') != -1) { + var source = getParameterByName('source', url); + if (source == '0') { + return ne_show_playlist(url, $http); + } + if (source == '1') { + return xm_show_playlist(url, $http); + } + if (source == '2') { + return qq_show_playlist(url, $http); + } + } + if (url.search('/playlist') != -1) { + var list_id = getParameterByName('list_id', url); + if (list_id.search('xmplaylist')!= -1) { + return xm_get_playlist(url, $http); + } + if (list_id.search('neplaylist')!= -1) { + return ne_get_playlist(url, $http); + } + if (list_id.search('qqplaylist')!= -1) { + return qq_get_playlist(url, $http); + } + + } + if (url.search('/search') != -1) { + var source = getParameterByName('source', url); + if (source == '0') { + return ne_search(url, $http, $httpParamSerializerJQLike); + } + if (source == '1') { + return xm_search(url, $http, $httpParamSerializerJQLike); + } + if (source == '2') { + return qq_search(url, $http, $httpParamSerializerJQLike); + } + } + if (url.search('/album') != -1) { + var album_id = getParameterByName('album_id', url); + if (album_id.search('xmalbum')!= -1) { + return xm_album(url, $http, $httpParamSerializerJQLike); + } + if (album_id.search('nealbum')!= -1) { + return ne_album(url, $http, $httpParamSerializerJQLike); + } + if (album_id.search('qqalbum')!= -1) { + return qq_album(url, $http, $httpParamSerializerJQLike); + } + } + if (url.search('/artist') != -1) { + var artist_id = getParameterByName('artist_id', url); + if (artist_id.search('xmartist')!= -1) { + return xm_artist(url, $http, $httpParamSerializerJQLike); + } + if (artist_id.search('neartist')!= -1) { + return ne_artist(url, $http, $httpParamSerializerJQLike); + } + if (artist_id.search('qqartist')!= -1) { + return qq_artist(url, $http, $httpParamSerializerJQLike); + } + } + + }, + bootstrapTrack: function(sound, track, callback){ + if (sound.url.search('http') != -1){ + callback(); + return; + } + if(track.source == 'xiami') { + xm_bootstrap_track(sound, track, callback, $http, $httpParamSerializerJQLike); + } + if(track.source == 'netease') { + ne_bootstrap_track(sound, track, callback, $http, $httpParamSerializerJQLike); + } + if(track.source == 'qq') { + qq_bootstrap_track(sound, track, callback, $http, $httpParamSerializerJQLike); + } + } + }; +}]); diff --git a/js/lowebutil.js b/js/lowebutil.js new file mode 100644 index 0000000..966f5b0 --- /dev/null +++ b/js/lowebutil.js @@ -0,0 +1,9 @@ +function getParameterByName(name, url) { + if (!url) url = window.location.href; + name = name.replace(/[\[\]]/g, "\\$&"); + var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), + results = regex.exec(url); + if (!results) return null; + if (!results[2]) return ''; + return decodeURIComponent(results[2].replace(/\+/g, " ")); +} \ No newline at end of file diff --git a/js/netease.js b/js/netease.js new file mode 100644 index 0000000..cc97018 --- /dev/null +++ b/js/netease.js @@ -0,0 +1,310 @@ +function ne_show_playlist(url, hm) { + var target_url = 'http://music.163.com/discover/playlist/'; + + return { + success: function(fn) { + var result = []; + hm.get(target_url).success(function(data) { + data = $.parseHTML(data); + $(data).find('.m-cvrlst li').each(function(){ + var default_playlist = { + 'cover_img_url' : '', + 'title': '', + 'list_id': '' + }; + 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; + default_playlist.list_id = 'neplaylist_' + getParameterByName('id',url); + result.push(default_playlist); + }); + return fn({"result":result}); + }); + } + }; +} + +function ne_get_playlist(url, hm) { + var list_id = getParameterByName('list_id', url).split('_').pop(); + var target_url = 'http://music.163.com/playlist?id=' + list_id; + return { + success: function(fn) { + hm.get(target_url).success(function(data) { + data = $.parseHTML(data); + var dataObj = $(data); + var info = { + 'list_id': list_id, + 'cover_img_url': dataObj.find('.u-cover img').attr('src'), + 'title': dataObj.find('.tit h2').text() + }; + var tracks = []; + var json_string = dataObj.find('textarea').val(); + var track_json_list = JSON.parse(json_string); + $.each(track_json_list, function(index, track_json){ + var default_track = { + 'id': '0', + 'title': '', + 'artist': '', + 'artist_id': 'neartist_0', + 'album': '', + 'album_id': 'nealbum_0', + 'source': 'netease', + 'source_url': 'http://www.xiami.com/song/0', + 'img_url': '', + 'url': '' + }; + default_track.id = 'netrack_' + track_json.id; + default_track.title = track_json.name; + default_track.artist = track_json.artists[0].name; + default_track.artist_id = 'neartist_' + track_json.artists[0].id; + default_track.album = track_json.album.name; + default_track.album_id = 'nealbum_' + track_json.album.id; + default_track.source_url = 'http://music.163.com/#/song?id=' + track_json.id; + default_track.img_url = track_json.album.picUrl; + default_track.url = default_track.id; + tracks.push(default_track); + }); + return fn({"info":info,"tracks":tracks,'is_mine':'0'}); + }); + } + }; +} + +function _create_secret_key(size) { + var result = []; + var choice = '012345679abcdef'.split(''); + for (var i=0; i').html(value).text(); +} + +function qq_show_playlist(url, hm) { + var target_url = 'http://i.y.qq.com/s.plcloud/fcgi-bin/fcg_get_diss_by_tag' + + '.fcg?categoryId=10000000&sortId=1&sin=0&ein=49&' + + 'format=jsonp&g_tk=5381&loginUin=0&hostUin=0&' + + 'format=jsonp&inCharset=GB2312&outCharset=utf-8' + + '¬ice=0&platform=yqq&jsonpCallback=' + + 'MusicJsonCallback&needNewCode=0'; + + return { + success: function(fn) { + var result = []; + hm({ + url:target_url, + method: 'GET', + transformResponse: undefined + }).success(function(data) { + data = data.slice('MusicJsonCallback('.length, -')'.length); + data = JSON.parse(data); + + var playlists = []; + $.each(data.data.list, function(index, item){ + var d = { + 'cover_img_url': item.imgurl, + 'title': htmlDecode(item.dissname), + 'list_id':'qqplaylist_' + item.dissid + }; + playlists.push(d); + }); + + return fn({"result":playlists}); + }); + } + }; +} + +function qq_get_image_url(qqimgid, img_type) { + var category = ''; + if(img_type == 'artist') { + category = 'mid_singer_300' + } + if(img_type == 'album') { + category = 'mid_album_300'; + } + var s = [category, qqimgid[qqimgid.length - 2], qqimgid[qqimgid.length - 1], qqimgid].join('/'); + var url = 'http://imgcache.qq.com/music/photo/' + s + '.jpg'; + return url; +} + +function qq_convert_song(song) { + d = { + 'id': 'qqtrack_' + song.songmid, + 'title': song.songname, + 'artist': song.singer[0].name, + 'artist_id': 'qqartist_' + song.singer[0].mid, + 'album': song.albumname, + 'album_id': 'qqalbum_' + song.albummid, + 'img_url': qq_get_image_url(song.albummid, 'album'), + 'source': 'qq', + 'source_url': 'http://y.qq.com/#type=song&mid=' + + song.songmid + '&tpl=yqq_song_detail', + 'url': 'qqtrack_' + song.songmid + } + return d +} + +function qq_get_playlist(url, hm) { + var list_id = getParameterByName('list_id', url).split('_').pop(); + + return { + success: function(fn) { + var target_url = 'http://i.y.qq.com/qzone-music/fcg-bin/fcg_ucc_getcdinfo_' + + 'byids_cp.fcg?type=1&json=1&utf8=1&onlysong=0&jsonpCallback=' + + 'jsonCallback&nosign=1&disstid=' + list_id +'&g_tk=5381&loginUin=0&hostUin=0' + + '&format=jsonp&inCharset=GB2312&outCharset=utf-8¬ice=0' + + '&platform=yqq&jsonpCallback=jsonCallback&needNewCode=0'; + hm({ + url:target_url, + method: 'GET', + transformResponse: undefined + }) + .success(function(data) { + data = data.slice('jsonCallback('.length, -')'.length); + data = JSON.parse(data); + + var info = { + 'cover_img_url': data.cdlist[0].logo, + 'title': data.cdlist[0].dissname, + 'id': 'qqplaylist_' + list_id + }; + + var tracks = []; + $.each(data.cdlist[0].songlist, function(index, item){ + var track = qq_convert_song(item); + tracks.push(track); + }); + return fn({"tracks":tracks, "info":info}); + }); + } + }; +} + +function qq_album(url, hm) { + var album_id = getParameterByName('album_id', url).split('_').pop(); + + return { + success: function(fn) { + var target_url = 'http://i.y.qq.com/v8/fcg-bin/fcg_v8_album_info_cp.fcg' + + '?platform=h5page&albummid=' + album_id + '&g_tk=938407465' + + '&uin=0&format=jsonp&inCharset=utf-8&outCharset=utf-8' + + '¬ice=0&platform=h5&needNewCode=1&_=1459961045571' + + '&jsonpCallback=asonglist1459961045566'; + hm({ + url: target_url, + method: 'GET', + transformResponse: undefined + }) + .success(function(data) { + data = data.slice(' asonglist1459961045566('.length, -')'.length); + data = JSON.parse(data); + + var info = { + 'cover_img_url': qq_get_image_url(album_id, 'album'), + 'title': data.data.name, + 'id': 'qqalbum_' + album_id + }; + + var tracks = []; + $.each(data.data.list, function(index, item){ + var track = qq_convert_song(item); + tracks.push(track); + }); + return fn({"tracks":tracks, "info":info}); + }); + } + }; +} + +function qq_artist(url, hm) { + var artist_id = getParameterByName('artist_id', url).split('_').pop(); + + return { + success: function(fn) { + var target_url = 'http://i.y.qq.com/v8/fcg-bin/fcg_v8_singer_track_cp.fcg' + + '?platform=h5page&order=listen&begin=0&num=50&singermid=' + artist_id + + '&g_tk=938407465&uin=0&format=jsonp&' + + 'inCharset=utf-8&outCharset=utf-8¬ice=0&platform=' + + 'h5&needNewCode=1&from=h5&_=1459960621777&' + + 'jsonpCallback=ssonglist1459960621772'; + hm({ + url: target_url, + method: 'GET', + transformResponse: undefined + }) + .success(function(data) { + data = data.slice(' ssonglist1459960621772('.length, -')'.length); + data = JSON.parse(data); + + var info = { + 'cover_img_url': qq_get_image_url(artist_id, 'artist'), + 'title': data.data.singer_name, + 'id': 'qqartist_' + artist_id + }; + + var tracks = []; + $.each(data.data.list, function(index, item){ + var track = qq_convert_song(item.musicData); + tracks.push(track); + }); + return fn({"tracks":tracks, "info":info}); + }); + } + }; +} + +function qq_search(url, hm, se) { + return { + success: function(fn) { + var keyword = getParameterByName('keywords', url); + var target_url = 'http://i.y.qq.com/s.music/fcgi-bin/search_for_qq_cp?' + + 'g_tk=938407465&uin=0&format=jsonp&inCharset=utf-8' + + '&outCharset=utf-8¬ice=0&platform=h5&needNewCode=1' + + '&w=' + keyword + '&zhidaqu=1&catZhida=1' + + '&t=0&flag=1&ie=utf-8&sem=1&aggr=0&perpage=20&n=20&p=1' + + '&remoteplace=txt.mqq.all&_=1459991037831&jsonpCallback=jsonp4'; + hm({ + url:target_url, + method: 'GET', + transformResponse: undefined + }) + .success(function(data) { + data = data.slice('jsonp4('.length, -')'.length); + data = JSON.parse(data); + var tracks = []; + $.each(data.data.song.list, function(index, item){ + var track = qq_convert_song(item); + tracks.push(track); + }); + return fn({"result":tracks}); + }); + } + }; +} + +function qq_bootstrap_track(sound, track, callback, hm, se) { + var target_url ='http://base.music.qq.com/fcgi-bin/fcg_musicexpress.fcg?' + + 'json=3&guid=780782017&g_tk=938407465&loginUin=0&hostUin=0&' + + 'format=jsonp&inCharset=GB2312&outCharset=GB2312¬ice=0&' + + 'platform=yqq&jsonpCallback=jsonCallback&needNewCode=0'; + + hm({ + url:target_url, + method: 'GET', + transformResponse: undefined + }) + .success(function(data) { + data = data.slice('jsonCallback('.length, -');'.length); + data = JSON.parse(data); + var token = data.key; + var url = 'http://cc.stream.qqmusic.qq.com/C200' + sound.url.slice('qqtrack_'.length) + '.m4a?vkey=' + + token + '&fromtag=0&guid=780782017'; + sound.url = url; + callback(); + }); +} \ No newline at end of file diff --git a/js/vendor/angular-soundmanager2.js b/js/vendor/angular-soundmanager2.js new file mode 100644 index 0000000..d947210 --- /dev/null +++ b/js/vendor/angular-soundmanager2.js @@ -0,0 +1,5293 @@ +/** @license + * + * SoundManager 2: JavaScript Sound for the Web + * ---------------------------------------------- + * http://schillmania.com/projects/soundmanager2/ + * + * Copyright (c) 2007, Scott Schiller. All rights reserved. + * Code provided under the BSD License: + * http://schillmania.com/projects/soundmanager2/license.txt + * + * V2.97a.20140901 + */ +/*global window, SM2_DEFER, sm2Debugger, console, document, navigator, setTimeout, setInterval, clearInterval, Audio, opera, module, define */ +/*jslint regexp: true, sloppy: true, white: true, nomen: true, plusplus: true, todo: true */ +/** + * About this file + * ------------------------------------------------------------------------------------- + * This is the fully-commented source version of the SoundManager 2 API, + * recommended for use during development and testing. + * + * See soundmanager2-nodebug-jsmin.js for an optimized build (~11KB with gzip.) + * http://schillmania.com/projects/soundmanager2/doc/getstarted/#basic-inclusion + * Alternately, serve this file with gzip for 75% compression savings (~30KB over HTTP.) + * + * You may notice and comments in this source; these are delimiters for + * debug blocks which are removed in the -nodebug builds, further optimizing code size. + * + * Also, as you may note: Whoa, reliable cross-platform/device audio support is hard! ;) + */ +(function(window, _undefined) { + "use strict"; + if(!window || !window.document) { + // Don't cross the [environment] streams. SM2 expects to be running in a browser, not under node.js etc. + // Additionally, if a browser somehow manages to fail this test, as Egon said: "It would be bad." + throw new Error('SoundManager requires a browser with window and document objects.'); + } + var soundManager = null; + /** + * 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 + */ + + 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]; + } + + 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); + }; + } + // + // 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); + }; + /** + * 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; + }; + 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(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; + + 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(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; + }; + + 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 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; + } + + 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(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') + }; + 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]; + } + } + } + }; + 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(); + /** + * 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 + }); + } + } // 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 + * 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. + } +}(window)); + +var ngSoundManager = angular.module('angularSoundManager', []) + .config(['$logProvider', function($logProvider){ + $logProvider.debugEnabled(false); + }]); + + +ngSoundManager.filter('humanTime', function () { + return function (input) { + function pad(d) { + return (d < 10) ? '0' + d.toString() : d.toString(); + } + + var min = (input / 1000 / 60) << 0, + sec = Math.floor((input / 1000) % 60); + + return pad(min) + ':' + pad(sec); + }; + }); + +ngSoundManager.factory('angularPlayer', ['$rootScope', '$log', + function($rootScope, $log) { + + var currentTrack = null, + repeat = false, + autoPlay = true, + isPlaying = false, + volume = 90, + trackProgress = 0, + playlist = [], + shuffle = false, + shufflelist= [], + shuffleCount = 0, + shuffleIndex = -1, + bootstrapTrack = null; + + return { + /** + * Initialize soundmanager, + * requires soundmanager2 to be loaded first + */ + init: function() { + if(typeof soundManager === 'undefined') { + alert('Please include SoundManager2 Library!'); + } + soundManager.setup({ + //url: '/path/to/swfs/', + //flashVersion: 9, + preferFlash: false, // prefer 100% HTML5 mode, where both supported + debugMode: false, // enable debugging output ($log.debug() with HTML fallback) + useHTML5Audio: true, + onready: function() { + //$log.debug('sound manager ready!'); + }, + ontimeout: function() { + alert('SM2 failed to start. Flash missing, blocked or security error?'); + alert('The status is ' + status.success + ', the error type is ' + status.error.type); + }, + defaultOptions: { + // set global default volume for all sound objects + autoLoad: false, // enable automatic loading (otherwise .load() will call with .play()) + autoPlay: false, // enable playing of file ASAP (much faster if "stream" is true) + from: null, // position to start playback within a sound (msec), see demo + loops: 1, // number of times to play the sound. Related: looping (API demo) + multiShot: false, // let sounds "restart" or "chorus" when played multiple times.. + multiShotEvents: false, // allow events (onfinish()) to fire for each shot, if supported. + onid3: null, // callback function for "ID3 data is added/available" + onload: null, // callback function for "load finished" + onstop: null, // callback for "user stop" + onfailure: 'nextTrack', // callback function for when playing fails + onpause: null, // callback for "pause" + onplay: null, // callback for "play" start + onresume: null, // callback for "resume" (pause toggle) + position: null, // offset (milliseconds) to seek to within downloaded sound. + 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), see demo + type: 'audio/mp3', // MIME-like hint for canPlay() tests, eg. 'audio/mp3' + usePolicyFile: false, // enable crossdomain.xml request for remote domains (for ID3/waveform access) + volume: volume, // self-explanatory. 0-100, the latter being the max. + whileloading: function() { + //soundManager._writeDebug('sound '+this.id+' loading, '+this.bytesLoaded+' of '+this.bytesTotal); + var trackLoaded = ((this.bytesLoaded/this.bytesTotal)*100); + $rootScope.$broadcast('track:loaded', trackLoaded); + }, + whileplaying: function() { + //soundManager._writeDebug('sound '+this.id+' playing, '+this.position+' of '+this.duration); + //broadcast current playing track id + currentTrack = this.id; + //$rootScope.$broadcast('track:id', this.id); + //broadcast current playing track progress + trackProgress = ((this.position / this.duration) * 100); + $rootScope.$broadcast('track:progress', trackProgress); + //broadcast track position + $rootScope.$broadcast('currentTrack:position', this.position); + //broadcast track duration + $rootScope.$broadcast('currentTrack:duration', this.duration); + }, + onfinish: function() { + soundManager._writeDebug(this.id + ' finished playing'); + if(autoPlay === true) { + //play next track if autoplay is on + //get your angular app + var elem = angular.element(document.querySelector('[ng-app]')); + //get the injector. + var injector = elem.injector(); + //get the service. + var angularPlayer = injector.get('angularPlayer'); + angularPlayer.nextTrack(); + $rootScope.$broadcast('track:id', currentTrack); + } + } + } + }); + soundManager.onready(function() { + $log.debug('song manager ready!'); + // Ready to use; soundManager.createSound() etc. can now be called. + var isSupported = soundManager.ok(); + $log.debug('is supported: ' + isSupported); + $rootScope.$broadcast('angularPlayer:ready', true); + }); + }, + /** + * To check if value is in array + */ + isInArray: function(array, value) { + for(var i = 0; i < array.length; i++) { + if(array[i].id === value) { + return i; + } + } + return false; + }, + /** + * getIndexByValue used by this factory + */ + getIndexByValue: function(array, value) { + for(var i = 0; i < array.length; i++) { + if(array[i] === value) { + return i; + } + } + return false; + }, + /** + * asyncLoop used by this factory + */ + asyncLoop: function(o) { + var i = -1; + var loop = function() { + i++; + if(i == o.length) { + o.callback(); + return; + } + o.functionToLoop(loop, i); + }; + loop(); //init + }, + setCurrentTrack: function(key) { + currentTrack = key; + }, + getCurrentTrack: function() { + return currentTrack; + }, + currentTrackData: function() { + var trackId = this.getCurrentTrack(); + var currentKey = this.isInArray(playlist, trackId); + return playlist[currentKey]; + }, + getPlaylist: function(key) { + if(typeof key === 'undefined') { + return playlist; + } else { + return playlist[key]; + } + }, + addToPlaylist: function(track) { + playlist.push(track); + //broadcast playlist + $rootScope.$broadcast('player:playlist', playlist); + }, + isTrackValid: function (track) { + if (typeof track == 'undefined') { + $log.debug('invalid track data'); + return false; + } + + if (track.url.indexOf("soundcloud") > -1) { + //if soundcloud url + if(typeof track.url == 'undefined') { + $log.debug('invalid soundcloud track url'); + return false; + } + } else { + if(soundManager.canPlayURL(track.url) !== true) { + $log.debug('invalid song url'); + return false; + } + } + }, + addTrack: function(track) { + //check if track itself is valid and if its url is playable + // disable track valid check because request url without + // proper extension name can be playable. + // if (!this.isTrackValid) { + // return null; + // } + + //check if song already does not exists then add to playlist + var inArrayKey = this.isInArray(this.getPlaylist(), track.id); + if(inArrayKey === false) { + //$log.debug('song does not exists in playlist'); + //add to sound manager + soundManager.createSound({ + id: track.id, + url: track.url + }); + shufflelist.push(track.id); + //add to playlist + this.addToPlaylist(track); + } + return track.id; + }, + addTrackArray: function(trackArray) { + for(var i = 0; i < trackArray.length; i++) { + var track = trackArray[i]; + //check if track itself is valid and if its url is playable + // if (!this.isTrackValid(track)) { + // console.log('track invalid'); + // continue; + // } + + //check if song already does not exists then add to playlist + var inArrayKey = this.isInArray(this.getPlaylist(), track.id); + if(inArrayKey === false) { + //$log.debug('song does not exists in playlist'); + //add to sound manager + soundManager.createSound({ + id: track.id, + url: track.url + }); + shufflelist.push(track.id); + //add to playlist + playlist.push(track); + } + } + //broadcast playlist + $rootScope.$broadcast('player:playlist', playlist); + }, + removeSong: function(song, index) { + //if this song is playing stop it + if(song === currentTrack) { + this.stop(); + } + //unload from soundManager + soundManager.destroySound(song); + //remove from playlist + playlist.splice(index, 1); + //remove from shufflelist + var removeIndex = this.getIndexByValue(shufflelist, song); + shufflelist.splice(removeIndex, 1); + if (removeIndex <= shuffleIndex) { + shuffleIndex --; + } + if (removeIndex <= shuffleCount - 1 ) { + shuffleCount --; + } + //once all done then broadcast + $rootScope.$broadcast('player:playlist', playlist); + }, + initPlayTrack: function(trackId, isResume) { + if(isResume !== true) { + //stop and unload currently playing track + this.stop(); + //set new track as current track + this.setCurrentTrack(trackId); + } + if (bootstrapTrack != null) { + var sound = soundManager.getSoundById(trackId); + bootstrapTrack(sound, this.currentTrackData(), function(){ + soundManager.play(trackId); + $rootScope.$broadcast('track:id', trackId); + //set as playing + isPlaying = true; + $rootScope.$broadcast('music:isPlaying', isPlaying); + }); + } + else { + soundManager.play(trackId); + $rootScope.$broadcast('track:id', trackId); + //set as playing + isPlaying = true; + $rootScope.$broadcast('music:isPlaying', isPlaying); + } + }, + play: function() { + var trackToPlay = null; + //check if no track loaded, else play loaded track + if(this.getCurrentTrack() === null) { + if(soundManager.soundIDs.length === 0) { + $log.debug('playlist is empty!'); + return; + } + trackToPlay = soundManager.soundIDs[0]; + this.initPlayTrack(trackToPlay); + } else { + trackToPlay = this.getCurrentTrack(); + this.initPlayTrack(trackToPlay, true); + } + }, + pause: function() { + soundManager.pause(this.getCurrentTrack()); + //set as not playing + isPlaying = false; + $rootScope.$broadcast('music:isPlaying', isPlaying); + }, + stop: function() { + //first pause it + this.pause(); + this.resetProgress(); + $rootScope.$broadcast('track:progress', trackProgress); + $rootScope.$broadcast('currentTrack:position', 0); + $rootScope.$broadcast('currentTrack:duration', 0); + soundManager.stopAll(); + soundManager.unload(this.getCurrentTrack()); + }, + playTrack: function(trackId) { + this.initPlayTrack(trackId); + }, + nextTrack: function() { + if (shuffle) { + if (shuffleCount == 0) { + if (shufflelist.length == 0){ + // initial shuffle related data + shufflelist = soundManager.soundIDs.slice(); + } + // swap current song to first element + var index = this.getIndexByValue(shufflelist, this.getCurrentTrack()); + var temp = shufflelist[index]; + shufflelist[index] = shufflelist[shuffleCount]; + shufflelist[shuffleCount] = temp; + shuffleIndex++; + shuffleCount++; + } + + if (shuffleIndex + 1 < shuffleCount) { + shuffleIndex++; + this.initPlayTrack(shufflelist[shuffleIndex]); + return; + } + + // choose one song from [shuffleCount, shufflelist.length-1] + if (shuffleCount == shufflelist.length) { + $log.debug("Shuffle list played finish, no next"); + return; + } + + var index = shuffleCount + Math.floor(Math.random() * (shufflelist.length-shuffleCount)); + // swap shuffle count and index + var temp = shufflelist[index]; + shufflelist[index] = shufflelist[shuffleCount]; + shufflelist[shuffleCount] = temp; + + shuffleIndex++; + this.initPlayTrack(shufflelist[shuffleIndex]); + shuffleCount++; + return; + } + if(this.getCurrentTrack() === null) { + $log.debug("Please click on Play before this action"); + return null; + } + var currentTrackKey = this.getIndexByValue(soundManager.soundIDs, this.getCurrentTrack()); + var nextTrackKey = +currentTrackKey + 1; + var nextTrack = soundManager.soundIDs[nextTrackKey]; + if(typeof nextTrack !== 'undefined') { + this.playTrack(nextTrack); + } else { + //if no next track found + if(repeat === true) { + //start first track if repeat is on + this.playTrack(soundManager.soundIDs[0]); + } else { + //breadcase not playing anything + isPlaying = false; + $rootScope.$broadcast('music:isPlaying', isPlaying); + } + } + }, + prevTrack: function() { + if (shuffle) { + if (shuffleIndex <= 0){ + // no prev found + return; + } + shuffleIndex--; + this.initPlayTrack(shufflelist[shuffleIndex]); + return; + } + if(this.getCurrentTrack() === null) { + $log.debug("Please click on Play before this action"); + return null; + } + var currentTrackKey = this.getIndexByValue(soundManager.soundIDs, this.getCurrentTrack()); + var prevTrackKey = +currentTrackKey - 1; + var prevTrack = soundManager.soundIDs[prevTrackKey]; + if(typeof prevTrack !== 'undefined') { + this.playTrack(prevTrack); + } else { + $log.debug('no prev track found!'); + } + }, + mute: function() { + if(soundManager.muted === true) { + soundManager.unmute(); + } else { + soundManager.mute(); + } + $rootScope.$broadcast('music:mute', soundManager.muted); + }, + getMuteStatus: function() { + return soundManager.muted; + }, + repeatToggle: function() { + if(repeat === true) { + repeat = false; + } else { + repeat = true; + } + $rootScope.$broadcast('music:repeat', repeat); + }, + getRepeatStatus: function() { + return repeat; + }, + getVolume: function() { + return volume; + }, + adjustVolume: function(increase) { + var changeVolume = function(volume) { + for(var i = 0; i < soundManager.soundIDs.length; i++) { + var mySound = soundManager.getSoundById(soundManager.soundIDs[i]); + mySound.setVolume(volume); + } + $rootScope.$broadcast('music:volume', volume); + }; + if(increase === true) { + if(volume < 100) { + volume = volume + 10; + changeVolume(volume); + } + } else { + if(volume > 0) { + volume = volume - 10; + changeVolume(volume); + } + } + }, + adjustVolumeSlider: function(value) { + var changeVolume = function(volume) { + for(var i = 0; i < soundManager.soundIDs.length; i++) { + var mySound = soundManager.getSoundById(soundManager.soundIDs[i]); + mySound.setVolume(volume); + } + $rootScope.$broadcast('music:volume', volume); + }; + changeVolume(value); + }, + clearPlaylist: function(callback) { + $log.debug('clear playlist'); + this.resetProgress(); + this.clearShuffle(); + //unload and destroy soundmanager sounds + var smIdsLength = soundManager.soundIDs.length; + this.asyncLoop({ + length: smIdsLength, + functionToLoop: function(loop, i) { + setTimeout(function() { + //custom code + soundManager.destroySound(soundManager.soundIDs[0]); + //custom code + loop(); + // accelerate remove speed reduce timeout to 0 + }, 0); + }, + callback: function() { + //callback custom code + $log.debug('All done!'); + //clear playlist + playlist = []; + $rootScope.$broadcast('player:playlist', playlist); + callback(true); + //callback custom code + } + }); + }, + resetProgress: function() { + trackProgress = 0; + }, + isPlayingStatus: function() { + return isPlaying; + }, + clearShuffle: function() { + shufflelist = []; + shuffleCount = 0; + shuffleIndex = -1; + }, + getShuffle: function(){ + return shuffle; + }, + toggleShuffle: function() { + shuffle = !shuffle; + this.clearShuffle(); + }, + setBootstrapTrack: function(fn){ + bootstrapTrack = fn; + } + }; + } +]); + + +ngSoundManager.directive('soundManager', ['$filter', '$timeout', 'angularPlayer', + function($filter, $timeout, angularPlayer) { + return { + restrict: "E", + link: function(scope, element, attrs) { + //init and load sound manager 2 + angularPlayer.init(); + scope.$on('track:progress', function(event, data) { + $timeout(function() { + scope.progress = data; + }); + }); + scope.$on('track:id', function(event, data) { + $timeout(function() { + scope.currentPlaying = angularPlayer.currentTrackData(); + }); + }); + scope.$on('currentTrack:position', function(event, data) { + $timeout(function() { + scope.currentPostion = $filter('humanTime')(data); + }); + }); + scope.$on('currentTrack:duration', function(event, data) { + $timeout(function() { + scope.currentDuration = $filter('humanTime')(data); + }); + }); + scope.isPlaying = false; + scope.$on('music:isPlaying', function(event, data) { + $timeout(function() { + scope.isPlaying = data; + }); + }); + scope.playlist = angularPlayer.getPlaylist(); //on load + scope.$on('player:playlist', function(event, data) { + $timeout(function() { + scope.playlist = data; + }); + }); + } + }; + } +]); + +ngSoundManager.directive('musicPlayer', ['angularPlayer', '$log', + function(angularPlayer, $log) { + return { + restrict: "EA", + scope: { + song: "=addSong" + }, + link: function(scope, element, attrs) { + var addToPlaylist = function() { + var trackId = angularPlayer.addTrack(scope.song); + //if request to play the track + if(attrs.musicPlayer === 'play') { + angularPlayer.playTrack(trackId); + } + }; + element.bind('click', function() { + $log.debug('adding song to playlist'); + addToPlaylist(); + }); + } + }; + } +]); + + +ngSoundManager.directive('playFromPlaylist', ['angularPlayer', function (angularPlayer) { + return { + restrict: "EA", + scope: { + song: "=playFromPlaylist" + }, + link: function (scope, element, attrs) { + element.bind('click', function (event) { + angularPlayer.playTrack(scope.song.id); + }); + } + }; + }]); + +ngSoundManager.directive('removeFromPlaylist', ['angularPlayer', + function(angularPlayer) { + return { + restrict: "EA", + scope: { + song: "=removeFromPlaylist" + }, + link: function(scope, element, attrs) { + element.bind('click', function(event) { + angularPlayer.removeSong(scope.song.id, attrs.index); + }); + } + }; + } +]); + +ngSoundManager.directive('seekTrack', ['angularPlayer', '$log', function (angularPlayer, $log) { + return { + restrict: "EA", + link: function (scope, element, attrs) { + + element.bind('click', function (event) { + if (angularPlayer.getCurrentTrack() === null) { + $log.debug('no track loaded'); + return; + } + + var sound = soundManager.getSoundById(angularPlayer.getCurrentTrack()); + + var getXOffset = function (event) { + var x = 0, element = event.target; + while (element && !isNaN(element.offsetLeft) && !isNaN(element.offsetTop)) { + x += element.offsetLeft - element.scrollLeft; + element = element.offsetParent; + } + return event.clientX - x; + }; + + var x = event.offsetX || getXOffset(event), + width = element[0].clientWidth, + duration = sound.durationEstimate; + + sound.setPosition((x / width) * duration); + }); + + } + }; + }]); + + +ngSoundManager.directive('playMusic', ['angularPlayer', function (angularPlayer) { + return { + restrict: "EA", + link: function (scope, element, attrs) { + + element.bind('click', function (event) { + angularPlayer.play(); + }); + + } + }; + }]); + +ngSoundManager.directive('pauseMusic', ['angularPlayer', function (angularPlayer) { + return { + restrict: "EA", + link: function (scope, element, attrs) { + element.bind('click', function (event) { + angularPlayer.pause(); + }); + } + }; + }]); + +ngSoundManager.directive('stopMusic', ['angularPlayer', function (angularPlayer) { + return { + restrict: "EA", + link: function (scope, element, attrs) { + element.bind('click', function (event) { + angularPlayer.stop(); + }); + } + }; + }]); + +ngSoundManager.directive('nextTrack', ['angularPlayer', function (angularPlayer) { + return { + restrict: "EA", + link: function (scope, element, attrs) { + + element.bind('click', function (event) { + angularPlayer.nextTrack(); + }); + + } + }; + }]); + +ngSoundManager.directive('prevTrack', ['angularPlayer', function (angularPlayer) { + return { + restrict: "EA", + link: function (scope, element, attrs) { + + element.bind('click', function (event) { + angularPlayer.prevTrack(); + }); + + } + }; + }]); + +ngSoundManager.directive('muteMusic', ['angularPlayer', function (angularPlayer) { + return { + restrict: "EA", + link: function (scope, element, attrs) { + + element.bind('click', function (event) { + angularPlayer.mute(); + }); + + scope.mute = angularPlayer.getMuteStatus(); + scope.$on('music:mute', function (event, data) { + scope.$apply(function () { + scope.mute = data; + }); + }); + + } + }; + }]); + +ngSoundManager.directive('repeatMusic', ['angularPlayer', function (angularPlayer) { + return { + restrict: "EA", + link: function (scope, element, attrs) { + + element.bind('click', function (event) { + angularPlayer.repeatToggle(); + }); + + scope.repeat = angularPlayer.getRepeatStatus(); + scope.$on('music:repeat', function (event, data) { + scope.$apply(function () { + scope.repeat = data; + }); + }); + } + }; + }]); + +ngSoundManager.directive('musicVolume', ['angularPlayer', + function(angularPlayer) { + return { + restrict: "EA", + link: function(scope, element, attrs) { + element.bind('click', function(event) { + if(attrs.type === 'increase') { + angularPlayer.adjustVolume(true); + } else { + angularPlayer.adjustVolume(false); + } + }); + scope.volume = angularPlayer.getVolume(); + scope.$on('music:volume', function(event, data) { + scope.$apply(function() { + scope.volume = data; + }); + }); + } + }; + } +]); + +ngSoundManager.directive('clearPlaylist', ['angularPlayer', '$log', + function(angularPlayer, $log) { + return { + restrict: "EA", + link: function(scope, element, attrs) { + element.bind('click', function(event) { + //first stop any playing music + angularPlayer.stop(); + angularPlayer.setCurrentTrack(null); + angularPlayer.clearPlaylist(function(data) { + $log.debug('all clear!'); + }); + }); + } + }; + } +]); + + +ngSoundManager.directive('playAll', ['angularPlayer', '$log', + function(angularPlayer, $log) { + return { + restrict: "EA", + scope: { + songs: '=playAll' + }, + link: function(scope, element, attrs) { + element.bind('click', function(event) { + //first clear the playlist + angularPlayer.clearPlaylist(function(data) { + $log.debug('cleared, ok now add to playlist'); + //add songs to playlist + for(var i = 0; i < scope.songs.length; i++) { + angularPlayer.addTrack(scope.songs[i]); + } + + if (attrs.play != 'false') { + //play first song + angularPlayer.play(); + } + }); + }); + } + }; + } +]); + + +ngSoundManager.directive('volumeBar', ['angularPlayer', + function(angularPlayer) { + return { + restrict: "EA", + link: function(scope, element, attrs) { + element.bind('click', function(event) { + var getXOffset = function(event) { + var x = 0, + element = event.target; + while(element && !isNaN(element.offsetLeft) && !isNaN(element.offsetTop)) { + x += element.offsetLeft - element.scrollLeft; + element = element.offsetParent; + } + return event.clientX - x; + }; + var x = event.offsetX || getXOffset(event), + width = element[0].clientWidth, + duration = 100; + var volume = (x / width) * duration; + angularPlayer.adjustVolumeSlider(volume); + }); + scope.volume = angularPlayer.getVolume(); + scope.$on('music:volume', function(event, data) { + scope.$apply(function() { + scope.volume = data; + }); + }); + } + }; + } +]); + +ngSoundManager.directive('playPauseToggle', ['angularPlayer', + function(angularPlayer) { + return { + restrict: "EA", + link: function(scope, element, attrs) { + scope.$on('music:isPlaying', function(event, data) { + //update html + if (data) { + if(typeof attrs.pause != 'undefined') { + element.html(attrs.pause); + } else { + element.html('Pause'); + } + } else { + if(typeof attrs.play != 'undefined') { + element.html(attrs.play); + } else { + element.html('Play'); + } + } + }); + + element.bind('click', function(event) { + if(angularPlayer.isPlayingStatus()) { + //if playing then pause + angularPlayer.pause(); + } else { + //else play if not playing + angularPlayer.play(); + + } + }); + } + }; + } +]); diff --git a/js/vendor/angular-ui-notification.js b/js/vendor/angular-ui-notification.js new file mode 100644 index 0000000..05f5adf --- /dev/null +++ b/js/vendor/angular-ui-notification.js @@ -0,0 +1,183 @@ +/** + * angular-ui-notification - Angular.js service providing simple notifications using Bootstrap 3 styles with css transitions for animating + * @author Alex_Crack + * @version v0.1.0 + * @link https://github.com/alexcrack/angular-ui-notification + * @license MIT + */ +angular.module('ui-notification',[]); + +angular.module('ui-notification').provider('Notification', function() { + + this.options = { + delay: 5000, + startTop: 10, + startRight: 10, + verticalSpacing: 10, + horizontalSpacing: 10, + positionX: 'right', + positionY: 'top', + replaceMessage: false, + templateUrl: 'angular-ui-notification.html' + }; + + this.setOptions = function(options) { + if (!angular.isObject(options)) throw new Error("Options should be an object!"); + this.options = angular.extend({}, this.options, options); + }; + + this.$get = ["$timeout", "$http", "$compile", "$templateCache", "$rootScope", "$injector", "$sce", "$q", "$window", function($timeout, $http, $compile, $templateCache, $rootScope, $injector, $sce, $q, $window) { + var options = this.options; + + var startTop = options.startTop; + var startRight = options.startRight; + var verticalSpacing = options.verticalSpacing; + var horizontalSpacing = options.horizontalSpacing; + var delay = options.delay; + + var messageElements = []; + var isResizeBound = false; + + var notify = function(args, t){ + var deferred = $q.defer(); + + if (typeof args !== 'object') { + args = {message:args}; + } + + args.scope = args.scope ? args.scope : $rootScope; + args.template = args.templateUrl ? args.templateUrl : options.templateUrl; + args.delay = !angular.isUndefined(args.delay) ? args.delay : delay; + args.type = t || options.type || ''; + args.positionY = args.positionY ? args.positionY : options.positionY; + args.positionX = args.positionX ? args.positionX : options.positionX; + args.replaceMessage = args.replaceMessage ? args.replaceMessage : options.replaceMessage; + + $http.get(args.template,{cache: $templateCache}).success(function(template) { + + var scope = args.scope.$new(); + scope.message = $sce.trustAsHtml(args.message); + scope.title = $sce.trustAsHtml(args.title); + scope.t = args.type.substr(0,1); + scope.delay = args.delay; + + var reposite = function() { + var j = 0; + var k = 0; + var lastTop = startTop; + var lastRight = startRight; + var lastPosition = []; + for(var i = messageElements.length - 1; i >= 0; i --) { + var element = messageElements[i]; + if (args.replaceMessage && i < messageElements.length - 1) { + element.addClass('killed'); + continue; + } + var elHeight = parseInt(element[0].offsetHeight); + var elWidth = parseInt(element[0].offsetWidth); + var position = lastPosition[element._positionY+element._positionX]; + + if ((top + elHeight) > window.innerHeight) { + position = startTop; + k ++; + j = 0; + } + + var top = (lastTop = position ? (j === 0 ? position : position + verticalSpacing) : startTop); + var right = lastRight + (k * (horizontalSpacing + elWidth)); + + element.css(element._positionY, top + 'px'); + if (element._positionX == 'center') { + element.css('left', parseInt(window.innerWidth / 2 - elWidth / 2) + 'px'); + } else { + element.css(element._positionX, right + 'px'); + } + + lastPosition[element._positionY+element._positionX] = top + elHeight; + + j ++; + } + }; + + var templateElement = $compile(template)(scope); + templateElement._positionY = args.positionY; + templateElement._positionX = args.positionX; + templateElement.addClass(args.type); + templateElement.bind('webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd click', function(e){ + e = e.originalEvent || e; + if (e.type === 'click' || (e.propertyName === 'opacity' && e.elapsedTime >= 1)){ + templateElement.remove(); + messageElements.splice(messageElements.indexOf(templateElement), 1); + scope.$destroy(); + reposite(); + } + }); + if (angular.isNumber(args.delay)) { + $timeout(function() { + templateElement.addClass('killed'); + }, args.delay); + } + + angular.element(document.getElementsByTagName('body')).append(templateElement); + var offset = -(parseInt(templateElement[0].offsetHeight) + 50); + templateElement.css(templateElement._positionY, offset + "px"); + messageElements.push(templateElement); + + scope._templateElement = templateElement; + + scope.kill = function(isHard) { + if (isHard) { + messageElements.splice(messageElements.indexOf(scope._templateElement), 1); + scope._templateElement.remove(); + scope.$destroy(); + $timeout(reposite); + } else { + scope._templateElement.addClass('killed'); + } + }; + + $timeout(reposite); + + if (!isResizeBound) { + angular.element($window).bind('resize', function(e) { + $timeout(reposite); + }); + isResizeBound = true; + } + + deferred.resolve(scope); + + }).error(function(data){ + throw new Error('Template ('+args.template+') could not be loaded. ' + data); + }); + + return deferred.promise; + }; + + notify.primary = function(args) { + return this(args, 'primary'); + }; + notify.error = function(args) { + return this(args, 'error'); + }; + notify.success = function(args) { + return this(args, 'success'); + }; + notify.info = function(args) { + return this(args, 'info'); + }; + notify.warning = function(args) { + return this(args, 'warning'); + }; + + notify.clearAll = function() { + angular.forEach(messageElements, function(element) { + element.addClass('killed'); + }); + }; + + return notify; + }]; +}); + +angular.module("ui-notification").run(["$templateCache", function($templateCache) {$templateCache.put("angular-ui-notification.html","

");}]); diff --git a/js/vendor/angular.min.js b/js/vendor/angular.min.js new file mode 100644 index 0000000..b10e3e9 --- /dev/null +++ b/js/vendor/angular.min.js @@ -0,0 +1,314 @@ +/* + AngularJS v1.5.5 + (c) 2010-2016 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(v){'use strict';function O(a){return function(){var b=arguments[0],d;d="["+(a?a+":":"")+b+"] http://errors.angularjs.org/1.5.5/"+(a?a+"/":"")+b;for(b=1;b").append(a).html();try{return a[0].nodeType===Ma?P(d):d.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+P(b)})}catch(c){return P(d)}} +function wc(a){try{return decodeURIComponent(a)}catch(b){}}function xc(a){var b={};q((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=wc(e),x(e)&&(f=x(f)?wc(f):!0,ua.call(b,e)?K(b[e])?b[e].push(f):b[e]=[b[e],f]:b[e]=f))});return b}function Rb(a){var b=[];q(a,function(a,c){K(a)?q(a,function(a){b.push(ja(c,!0)+(!0===a?"":"="+ja(a,!0)))}):b.push(ja(c,!0)+(!0===a?"":"="+ja(a,!0)))});return b.length?b.join("&"):""} +function ob(a){return ja(a,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function ja(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 de(a,b){var d,c,e=Na.length;for(c=0;c/,">"));}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=bb(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!/;v&&e.test(v.name)&&(d.debugInfoEnabled=!0,v.name=v.name.replace(e,""));if(v&&!f.test(v.name))return c();v.name=v.name.replace(f,"");ea.resumeBootstrap=function(a){q(a,function(a){b.push(a)});return c()};E(ea.resumeDeferredBootstrap)&&ea.resumeDeferredBootstrap()}function fe(){v.name= +"NG_ENABLE_DEBUG_INFO!"+v.name;v.location.reload()}function ge(a){a=ea.element(a).injector();if(!a)throw Aa("test");return a.get("$$testability")}function zc(a,b){b=b||"_";return a.replace(he,function(a,c){return(c?b:"")+a.toLowerCase()})}function ie(){var a;if(!Ac){var b=pb();(Z=y(b)?v.jQuery:b?v[b]:void 0)&&Z.fn.on?(B=Z,R(Z.fn,{scope:Oa.scope,isolateScope:Oa.isolateScope,controller:Oa.controller,injector:Oa.injector,inheritedData:Oa.inheritedData}),a=Z.cleanData,Z.cleanData=function(b){for(var c, +e=0,f;null!=(f=b[e]);e++)(c=Z._data(f,"events"))&&c.$destroy&&Z(f).triggerHandler("$destroy");a(b)}):B=U;ea.element=B;Ac=!0}}function qb(a,b,d){if(!a)throw Aa("areq",b||"?",d||"required");return a}function Pa(a,b,d){d&&K(a)&&(a=a[a.length-1]);qb(E(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 Aa("badname",b);}function Bc(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=$a(f,d.childNodes);d=e.firstChild;d.textContent=""}else f.push(b.createTextNode(a));e.textContent="";e.innerHTML="";q(f,function(a){e.appendChild(a)}); +return e}function Mc(a,b){var d=a.parentNode;d&&d.replaceChild(b,a);b.appendChild(a)}function U(a){if(a instanceof U)return a;var b;F(a)&&(a=V(a),b=!0);if(!(this instanceof U)){if(b&&"<"!=a.charAt(0))throw Ub("nosel");return new U(a)}if(b){b=v.document;var d;a=(d=Mf.exec(a))?[b.createElement(d[1])]:(d=Lc(a,b))?d.childNodes:[]}Nc(this,a)}function Vb(a){return a.cloneNode(!0)}function ub(a,b){b||db(a);if(a.querySelectorAll)for(var d=a.querySelectorAll("*"),c=0,e=d.length;c=Ca?!1:"function"===typeof a&&/^(?:class\s|constructor\()/.test(Function.prototype.toString.call(a));return d?(c.unshift(null),new (Function.prototype.bind.apply(a,c))):a.apply(b,c)},instantiate:function(a,b,c){var d=K(a)?a[a.length-1]:a;a=e(a,b,c);a.unshift(null);return new (Function.prototype.bind.apply(d, +a))},get:d,annotate:bb.$$annotate,has:function(b){return m.hasOwnProperty(b+"Provider")||a.hasOwnProperty(b)}}}b=!0===b;var k={},l=[],n=new Ra([],!0),m={$provide:{provider:d(c),factory:d(f),service:d(function(a,b){return f(a,["$injector",function(a){return a.instantiate(b)}])}),value:d(function(a,b){return f(a,da(b),!1)}),constant:d(function(a,b){Qa(a,"constant");m[a]=b;N[a]=b}),decorator:function(a,b){var c=r.get(a+"Provider"),d=c.$get;c.$get=function(){var a=w.invoke(d,c);return w.invoke(b,null, +{$delegate:a})}}}},r=m.$injector=h(m,function(a,b){ea.isString(b)&&l.push(b);throw Ga("unpr",l.join(" <- "));}),N={},M=h(N,function(a,b){var c=r.get(a+"Provider",b);return w.invoke(c.$get,c,void 0,a)}),w=M;m.$injectorProvider={$get:da(M)};var p=g(a),w=M.get("$injector");w.strictDi=b;q(p,function(a){a&&w.invoke(a)});return w}function We(){var a=!0;this.disableAutoScrolling=function(){a=!1};this.$get=["$window","$location","$rootScope",function(b,d,c){function e(a){var b=null;Array.prototype.some.call(a, +function(a){if("a"===va(a))return b=a,!0});return b}function f(a){if(a){a.scrollIntoView();var c;c=g.yOffset;E(c)?c=c():Ob(c)?(c=c[0],c="fixed"!==b.getComputedStyle(c).position?0:c.getBoundingClientRect().bottom):Q(c)||(c=0);c&&(a=a.getBoundingClientRect().top,b.scrollBy(0,a-c))}else b.scrollTo(0,0)}function g(a){a=F(a)?a:d.hash();var b;a?(b=h.getElementById(a))?f(b):(b=e(h.getElementsByName(a)))?f(b):"top"===a&&f(null):f(null)}var h=b.document;a&&c.$watch(function(){return d.hash()},function(a,b){a=== +b&&""===a||Of(function(){c.$evalAsync(g)})});return g}]}function fb(a,b){if(!a&&!b)return"";if(!a)return b;if(!b)return a;K(a)&&(a=a.join(" "));K(b)&&(b=b.join(" "));return a+" "+b}function Xf(a){F(a)&&(a=a.split(" "));var b=T();q(a,function(a){a.length&&(b[a]=!0)});return b}function Ha(a){return G(a)?a:{}}function Yf(a,b,d,c){function e(a){try{a.apply(null,za.call(arguments,1))}finally{if(M--,0===M)for(;w.length;)try{w.pop()()}catch(b){d.error(b)}}}function f(){u=null;g();h()}function g(){p=I(); +p=y(p)?null:p;pa(p,L)&&(p=L);L=p}function h(){if(t!==k.url()||H!==p)t=k.url(),H=p,q(J,function(a){a(k.url(),p)})}var k=this,l=a.location,n=a.history,m=a.setTimeout,r=a.clearTimeout,N={};k.isMock=!1;var M=0,w=[];k.$$completeOutstandingRequest=e;k.$$incOutstandingRequestCount=function(){M++};k.notifyWhenNoOutstandingRequests=function(a){0===M?a():w.push(a)};var p,H,t=l.href,z=b.find("base"),u=null,I=c.history?function(){try{return n.state}catch(a){}}:C;g();H=p;k.url=function(b,d,e){y(e)&&(e=null);l!== +a.location&&(l=a.location);n!==a.history&&(n=a.history);if(b){var f=H===e;if(t===b&&(!c.history||f))return k;var h=t&&Ia(t)===Ia(b);t=b;H=e;if(!c.history||h&&f){if(!h||u)u=b;d?l.replace(b):h?(d=l,e=b.indexOf("#"),e=-1===e?"":b.substr(e),d.hash=e):l.href=b;l.href!==b&&(u=b)}else n[d?"replaceState":"pushState"](e,"",b),g(),H=p;return k}return u||l.href.replace(/%27/g,"'")};k.state=function(){return p};var J=[],D=!1,L=null;k.onUrlChange=function(b){if(!D){if(c.history)B(a).on("popstate",f);B(a).on("hashchange", +f);D=!0}J.push(b);return b};k.$$applicationDestroyed=function(){B(a).off("hashchange popstate",f)};k.$$checkUrlChange=h;k.baseHref=function(){var a=z.attr("href");return a?a.replace(/^(https?\:)?\/\/[^\/]*/,""):""};k.defer=function(a,b){var c;M++;c=m(function(){delete N[c];e(a)},b||0);N[c]=!0;return c};k.defer.cancel=function(a){return N[a]?(delete N[a],r(a),e(C),!0):!1}}function cf(){this.$get=["$window","$log","$sniffer","$document",function(a,b,d,c){return new Yf(a,c,b,d)}]}function df(){this.$get= +function(){function a(a,c){function e(a){a!=m&&(r?r==a&&(r=a.n):r=a,f(a.n,a.p),f(a,m),m=a,m.n=null)}function f(a,b){a!=b&&(a&&(a.p=b),b&&(b.n=a))}if(a in b)throw O("$cacheFactory")("iid",a);var g=0,h=R({},c,{id:a}),k=T(),l=c&&c.capacity||Number.MAX_VALUE,n=T(),m=null,r=null;return b[a]={put:function(a,b){if(!y(b)){if(ll&&this.remove(r.key);return b}},get:function(a){if(l";b=na.firstChild.attributes;var d=b[0];b.removeNamedItem(d.name);d.value=c;a.attributes.setNamedItem(d)}function A(a,b){try{a.addClass(b)}catch(c){}}function ba(a,b,c,d,e){a instanceof B||(a=B(a));for(var f=/\S+/,g=0,h=a.length;g").append(a).html())):c?Oa.clone.call(a):a;if(g)for(var h in g)d.data("$"+h+"Controller",g[h].instance);ba.$$addScopeInfo(d,b);c&&c(d,b);l&&l(b,d,d,f);return d}}function s(a,b,c,d,e,f){function g(a, +c,d,e){var f,k,l,m,n,t,p;if(r)for(p=Array(c.length),m=0;mA.priority)break;if(v=A.scope)A.templateUrl||(G(v)?(W("new/isolated scope",D||r,A,z),D=A):W("new/isolated scope",D,A,z)),r=r||A;M=A.name;if(!ka&&(A.replace&&(A.templateUrl||A.template)||A.transclude&&!A.$$tlb)){for(v=F+1;ka=a[v++];)if(ka.transclude&&!ka.$$tlb||ka.replace&&(ka.templateUrl||ka.template)){C=!0;break}ka=!0}!A.templateUrl&&A.controller&&(v=A.controller,I=I||T(),W("'"+M+"' controller",I[M],A,z),I[M]=A);if(v=A.transclude)if(u=!0,A.$$tlb||(W("transclusion",w,A,z),w=A),"element"==v)H= +!0,t=A.priority,$=z,z=d.$$element=B(ba.$$createComment(M,d[M])),b=z[0],da(f,za.call($,0),b),$[0].$$parentNode=$[0].parentNode,s=Yb(C,$,e,t,g&&g.name,{nonTlbTranscludeDirective:w});else{var la=T();$=B(Vb(b)).contents();if(G(v)){$=[];var Y=T(),X=T();q(v,function(a,b){var c="?"===a.charAt(0);a=c?a.substring(1):a;Y[a]=b;la[b]=null;X[b]=c});q(z.contents(),function(a){var b=Y[xa(va(a))];b?(X[b]=!0,la[b]=la[b]||[],la[b].push(a)):$.push(a)});q(X,function(a,b){if(!a)throw ga("reqslot",b);});for(var Z in la)la[Z]&& +(la[Z]=Yb(C,la[Z],e))}z.empty();s=Yb(C,$,e,void 0,void 0,{needsNewScope:A.$$isolateScope||A.$$newScope});s.$$slots=la}if(A.template)if(L=!0,W("template",J,A,z),J=A,v=E(A.template)?A.template(z,d):A.template,v=ta(v),A.replace){g=A;$=Tb.test(v)?Yc(ca(A.templateNamespace,V(v))):[];b=$[0];if(1!=$.length||1!==b.nodeType)throw ga("tplrt",M,"");da(f,z,b);Ba={$attr:{}};v=x(b,[],Ba);var ea=a.splice(F+1,a.length-(F+1));(D||r)&&Zc(v,D,r);a=a.concat(v).concat(ea);U(d,Ba);Ba=a.length}else z.html(v);if(A.templateUrl)L= +!0,W("template",J,A,z),J=A,A.replace&&(g=A),n=aa(a.splice(F,a.length-F),z,d,f,u&&s,h,k,{controllerDirectives:I,newScopeDirective:r!==A&&r,newIsolateScopeDirective:D,templateDirective:J,nonTlbTranscludeDirective:w}),Ba=a.length;else if(A.compile)try{Sa=A.compile(z,d,s),E(Sa)?m(null,Sa,P,Q):Sa&&m(Sa.pre,Sa.post,P,Q)}catch(fa){c(fa,wa(z))}A.terminal&&(n.terminal=!0,t=Math.max(t,A.priority))}n.scope=r&&!0===r.scope;n.transcludeOnThisElement=u;n.templateOnThisElement=L;n.transclude=s;l.hasElementTranscludeDirective= +H;return n}function gb(a,b,c,d){var e;if(F(b)){var f=b.match(k);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.inheritedData(h):c.data(h)}if(!e&&!f)throw ga("ctreq",b,a);}else if(K(b))for(e=[],g=0,f=b.length;gn.priority)&&-1!=n.restrict.indexOf(g)){l&&(n=Pb(n,{$$start:l,$$end:m}));if(!n.$$bindings){var I= +n,D=n,A=n.name,J={isolateScope:null,bindToController:null};G(D.scope)&&(!0===D.bindToController?(J.bindToController=d(D.scope,A,!0),J.isolateScope={}):J.isolateScope=d(D.scope,A,!1));G(D.bindToController)&&(J.bindToController=d(D.bindToController,A,!0));if(G(J.bindToController)){var w=D.controller,z=D.controllerAs;if(!w)throw ga("noctrl",A);if(!Uc(w,z))throw ga("noident",A);}var u=I.$$bindings=J;G(u.isolateScope)&&(n.$$isolateBindings=u.isolateScope)}b.push(n);k=n}}catch(L){c(L)}}return k}function Q(b){if(e.hasOwnProperty(b))for(var c= +a.get(b+"Directive"),d=0,f=c.length;d"+b+"";return c.childNodes[0].childNodes;default:return b}}function ea(a,b){if("srcdoc"==b)return I.HTML;var c=va(a);if("xlinkHref"==b||"form"==c&&"action"==b||"img"!=c&&("src"==b||"ngSrc"==b))return I.RESOURCE_URL}function fa(a,c,d,e,f){var g=ea(a,e);f=h[e]||f;var k=b(d,!0,g,f);if(k){if("multiple"===e&&"select"===va(a))throw ga("selmulti",wa(a));c.push({priority:100,compile:function(){return{pre:function(a, +c,h){c=h.$$observers||(h.$$observers=T());if(l.test(e))throw ga("nodomevents");var m=h[e];m!==d&&(k=m&&b(m,!0,g,f),d=m);k&&(h[e]=k(a),(c[e]||(c[e]=[])).$$inter=!0,(h.$$observers&&h.$$observers[e].$$scope||a).$watch(k,function(a,b){"class"===e&&a!=b?h.$updateClass(a,b):h.$set(e,a)}))}}}})}}function da(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--;)8===a[b].nodeType&&Zf.call(a,b,1);return a}function Uc(a, +b){if(b&&F(b))return b;if(F(a)){var d=bd.exec(a);if(d)return d[3]}}function ef(){var a={},b=!1;this.has=function(b){return a.hasOwnProperty(b)};this.register=function(b,c){Qa(b,"controller");G(b)?R(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||!G(a.$scope))throw O("$controller")("noscp",d,b);a.$scope[b]=c}return function(f,g,h,k){var l,n,m;h=!0===h;k&&F(k)&&(m=k);if(F(f)){k=f.match(bd);if(!k)throw $f("ctrlfmt",f);n=k[1];m= +m||k[3];f=a.hasOwnProperty(n)?a[n]:Bc(g.$scope,n,!0)||(b?Bc(c,n,!0):void 0);Pa(f,n,!0)}if(h)return h=(K(f)?f[f.length-1]:f).prototype,l=Object.create(h||null),m&&e(g,m,l,n||f.name),R(function(){var a=d.invoke(f,l,g,n);a!==l&&(G(a)||E(a))&&(l=a,m&&e(g,m,l,n||f.name));return l},{instance:l,identifier:m});l=d.instantiate(f,g,n);m&&e(g,m,l,n||f.name);return l}}]}function ff(){this.$get=["$window",function(a){return B(a.document)}]}function gf(){this.$get=["$log",function(a){return function(b,d){a.error.apply(a, +arguments)}}]}function $b(a){return G(a)?fa(a)?a.toISOString():ab(a):a}function mf(){this.$get=function(){return function(a){if(!a)return"";var b=[];pc(a,function(a,c){null===a||y(a)||(K(a)?q(a,function(a){b.push(ja(c)+"="+ja($b(a)))}):b.push(ja(c)+"="+ja($b(a))))});return b.join("&")}}}function nf(){this.$get=function(){return function(a){function b(a,e,f){null===a||y(a)||(K(a)?q(a,function(a,c){b(a,e+"["+(G(a)?c:"")+"]")}):G(a)&&!fa(a)?pc(a,function(a,c){b(a,e+(f?"":"[")+c+(f?"":"]"))}):d.push(ja(e)+ +"="+ja($b(a))))}if(!a)return"";var d=[];b(a,"",!0);return d.join("&")}}}function ac(a,b){if(F(a)){var d=a.replace(ag,"").trim();if(d){var c=b("Content-Type");(c=c&&0===c.indexOf(cd))||(c=(c=d.match(bg))&&cg[c[0]].test(d));c&&(a=uc(d))}}return a}function dd(a){var b=T(),d;F(a)?q(a.split("\n"),function(a){d=a.indexOf(":");var e=P(V(a.substr(0,d)));a=V(a.substr(d+1));e&&(b[e]=b[e]?b[e]+", "+a:a)}):G(a)&&q(a,function(a,d){var f=P(d),g=V(a);f&&(b[f]=b[f]?b[f]+", "+g:g)});return b}function ed(a){var b; +return function(d){b||(b=dd(a));return d?(d=b[P(d)],void 0===d&&(d=null),d):b}}function fd(a,b,d,c){if(E(c))return c(a,b,d);q(c,function(c){a=c(a,b,d)});return a}function lf(){var a=this.defaults={transformResponse:[ac],transformRequest:[function(a){return G(a)&&"[object File]"!==ma.call(a)&&"[object Blob]"!==ma.call(a)&&"[object FormData]"!==ma.call(a)?ab(a):a}],headers:{common:{Accept:"application/json, text/plain, */*"},post:ha(bc),put:ha(bc),patch:ha(bc)},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN", +paramSerializer:"$httpParamSerializer"},b=!1;this.useApplyAsync=function(a){return x(a)?(b=!!a,this):b};var d=!0;this.useLegacyPromiseExtensions=function(a){return x(a)?(d=!!a,this):d};var c=this.interceptors=[];this.$get=["$httpBackend","$$cookieReader","$cacheFactory","$rootScope","$q","$injector",function(e,f,g,h,k,l){function n(b){function c(a){var b=R({},a);b.data=fd(a.data,a.headers,a.status,f.transformResponse);a=a.status;return 200<=a&&300>a?b:k.reject(b)}function e(a,b){var c,d={};q(a,function(a, +e){E(a)?(c=a(b),null!=c&&(d[e]=c)):d[e]=a});return d}if(!G(b))throw O("$http")("badreq",b);if(!F(b.url))throw O("$http")("badreq",b.url);var f=R({method:"get",transformRequest:a.transformRequest,transformResponse:a.transformResponse,paramSerializer:a.paramSerializer},b);f.headers=function(b){var c=a.headers,d=R({},b.headers),f,g,h,c=R({},c.common,c[P(b.method)]);a:for(f in c){g=P(f);for(h in d)if(P(h)===g)continue a;d[f]=c[f]}return e(d,ha(b))}(b);f.method=sb(f.method);f.paramSerializer=F(f.paramSerializer)? +l.get(f.paramSerializer):f.paramSerializer;var g=[function(b){var d=b.headers,e=fd(b.data,ed(d),void 0,b.transformRequest);y(e)&&q(d,function(a,b){"content-type"===P(b)&&delete d[b]});y(b.withCredentials)&&!y(a.withCredentials)&&(b.withCredentials=a.withCredentials);return m(b,e).then(c,c)},void 0],h=k.when(f);for(q(M,function(a){(a.request||a.requestError)&&g.unshift(a.request,a.requestError);(a.response||a.responseError)&&g.push(a.response,a.responseError)});g.length;){b=g.shift();var n=g.shift(), +h=h.then(b,n)}d?(h.success=function(a){Pa(a,"fn");h.then(function(b){a(b.data,b.status,b.headers,f)});return h},h.error=function(a){Pa(a,"fn");h.then(null,function(b){a(b.data,b.status,b.headers,f)});return h}):(h.success=gd("success"),h.error=gd("error"));return h}function m(c,d){function g(a){if(a){var c={};q(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 l(a,c,d,e){function f(){m(c,a,d,e)}L&&(200<=a&&300>a?L.put(A,[a,c,dd(d), +e]):L.remove(A));b?h.$applyAsync(f):(f(),h.$$phase||h.$apply())}function m(a,b,d,e){b=-1<=b?b:0;(200<=b&&300>b?J.resolve:J.reject)({data:a,status:b,headers:ed(d),config:c,statusText:e})}function u(a){m(a.data,a.status,ha(a.headers()),a.statusText)}function I(){var a=n.pendingRequests.indexOf(c);-1!==a&&n.pendingRequests.splice(a,1)}var J=k.defer(),D=J.promise,L,S,M=c.headers,A=r(c.url,c.paramSerializer(c.params));n.pendingRequests.push(c);D.then(I,I);!c.cache&&!a.cache||!1===c.cache||"GET"!==c.method&& +"JSONP"!==c.method||(L=G(c.cache)?c.cache:G(a.cache)?a.cache:N);L&&(S=L.get(A),x(S)?S&&E(S.then)?S.then(u,u):K(S)?m(S[1],S[0],ha(S[2]),S[3]):m(S,200,{},"OK"):L.put(A,D));y(S)&&((S=hd(c.url)?f()[c.xsrfCookieName||a.xsrfCookieName]:void 0)&&(M[c.xsrfHeaderName||a.xsrfHeaderName]=S),e(c.method,A,d,l,M,c.timeout,c.withCredentials,c.responseType,g(c.eventHandlers),g(c.uploadEventHandlers)));return D}function r(a,b){0=l&&(t.resolve(p), +w(z.$$intervalId),delete g[z.$$intervalId]);H||a.$apply()},k);g[z.$$intervalId]=t;return z}var g={};f.cancel=function(a){return a&&a.$$intervalId in g?(g[a.$$intervalId].reject("canceled"),b.clearInterval(a.$$intervalId),delete g[a.$$intervalId],!0):!1};return f}]}function cc(a){a=a.split("/");for(var b=a.length;b--;)a[b]=ob(a[b]);return a.join("/")}function id(a,b){var d=ra(a);b.$$protocol=d.protocol;b.$$host=d.hostname;b.$$port=X(d.port)||eg[d.protocol]||null}function jd(a,b){var d="/"!==a.charAt(0); +d&&(a="/"+a);var c=ra(a);b.$$path=decodeURIComponent(d&&"/"===c.pathname.charAt(0)?c.pathname.substring(1):c.pathname);b.$$search=xc(c.search);b.$$hash=decodeURIComponent(c.hash);b.$$path&&"/"!=b.$$path.charAt(0)&&(b.$$path="/"+b.$$path)}function na(a,b){if(0===b.indexOf(a))return b.substr(a.length)}function Ia(a){var b=a.indexOf("#");return-1==b?a:a.substr(0,b)}function hb(a){return a.replace(/(#.+)|#$/,"$1")}function dc(a,b,d){this.$$html5=!0;d=d||"";id(a,this);this.$$parse=function(a){var d=na(b, +a);if(!F(d))throw Eb("ipthprfx",a,b);jd(d,this);this.$$path||(this.$$path="/");this.$$compose()};this.$$compose=function(){var a=Rb(this.$$search),d=this.$$hash?"#"+ob(this.$$hash):"";this.$$url=cc(this.$$path)+(a?"?"+a:"")+d;this.$$absUrl=b+this.$$url.substr(1)};this.$$parseLinkUrl=function(c,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;x(f=na(a,c))?(g=f,g=x(f=na(d,f))?b+(na("/",f)||f):a+g):x(f=na(b,c))?g=b+f:b==c+"/"&&(g=b);g&&this.$$parse(g);return!!g}}function ec(a,b,d){id(a,this); +this.$$parse=function(c){var e=na(a,c)||na(b,c),f;y(e)||"#"!==e.charAt(0)?this.$$html5?f=e:(f="",y(e)&&(a=c,this.replace())):(f=na(d,e),y(f)&&(f=e));jd(f,this);c=this.$$path;var e=a,g=/^\/[A-Z]:(\/.*)/;0===f.indexOf(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=Rb(this.$$search),e=this.$$hash?"#"+ob(this.$$hash):"";this.$$url=cc(this.$$path)+(b?"?"+b:"")+e;this.$$absUrl=a+(this.$$url?d+this.$$url:"")};this.$$parseLinkUrl= +function(b,d){return Ia(a)==Ia(b)?(this.$$parse(b),!0):!1}}function kd(a,b,d){this.$$html5=!0;ec.apply(this,arguments);this.$$parseLinkUrl=function(c,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;a==Ia(c)?f=c:(g=na(b,c))?f=a+d+g:b===c+"/"&&(f=b);f&&this.$$parse(f);return!!f};this.$$compose=function(){var b=Rb(this.$$search),e=this.$$hash?"#"+ob(this.$$hash):"";this.$$url=cc(this.$$path)+(b?"?"+b:"")+e;this.$$absUrl=a+d+this.$$url}}function Fb(a){return function(){return this[a]}}function ld(a, +b){return function(d){if(y(d))return this[a];this[a]=b(d);this.$$compose();return this}}function qf(){var a="",b={enabled:!1,requireBase:!0,rewriteLinks:!0};this.hashPrefix=function(b){return x(b)?(a=b,this):a};this.html5Mode=function(a){return Da(a)?(b.enabled=a,this):G(a)?(Da(a.enabled)&&(b.enabled=a.enabled),Da(a.requireBase)&&(b.requireBase=a.requireBase),Da(a.rewriteLinks)&&(b.rewriteLinks=a.rewriteLinks),this):b};this.$get=["$rootScope","$browser","$sniffer","$rootElement","$window",function(d, +c,e,f,g){function h(a,b,d){var e=l.url(),f=l.$$state;try{c.url(a,b,d),l.$$state=c.state()}catch(g){throw l.url(e),l.$$state=f,g;}}function k(a,b){d.$broadcast("$locationChangeSuccess",l.absUrl(),a,l.$$state,b)}var l,n;n=c.baseHref();var m=c.url(),r;if(b.enabled){if(!n&&b.requireBase)throw Eb("nobase");r=m.substring(0,m.indexOf("/",m.indexOf("//")+2))+(n||"/");n=e.history?dc:kd}else r=Ia(m),n=ec;var N=r.substr(0,Ia(r).lastIndexOf("/")+1);l=new n(r,N,"#"+a);l.$$parseLinkUrl(m,m);l.$$state=c.state(); +var q=/^\s*(javascript|mailto):/i;f.on("click",function(a){if(b.rewriteLinks&&!a.ctrlKey&&!a.metaKey&&!a.shiftKey&&2!=a.which&&2!=a.button){for(var e=B(a.target);"a"!==va(e[0]);)if(e[0]===f[0]||!(e=e.parent())[0])return;var h=e.prop("href"),k=e.attr("href")||e.attr("xlink:href");G(h)&&"[object SVGAnimatedString]"===h.toString()&&(h=ra(h.animVal).href);q.test(h)||!h||e.attr("target")||a.isDefaultPrevented()||!l.$$parseLinkUrl(h,k)||(a.preventDefault(),l.absUrl()!=c.url()&&(d.$apply(),g.angular["ff-684208-preventDefault"]= +!0))}});hb(l.absUrl())!=hb(m)&&c.url(l.absUrl(),!0);var w=!0;c.onUrlChange(function(a,b){y(na(N,a))?g.location.href=a:(d.$evalAsync(function(){var c=l.absUrl(),e=l.$$state,f;a=hb(a);l.$$parse(a);l.$$state=b;f=d.$broadcast("$locationChangeStart",a,c,b,e).defaultPrevented;l.absUrl()===a&&(f?(l.$$parse(c),l.$$state=e,h(c,!1,e)):(w=!1,k(c,e)))}),d.$$phase||d.$digest())});d.$watch(function(){var a=hb(c.url()),b=hb(l.absUrl()),f=c.state(),g=l.$$replace,m=a!==b||l.$$html5&&e.history&&f!==l.$$state;if(w|| +m)w=!1,d.$evalAsync(function(){var b=l.absUrl(),c=d.$broadcast("$locationChangeStart",b,a,l.$$state,f).defaultPrevented;l.absUrl()===b&&(c?(l.$$parse(a),l.$$state=f):(m&&h(b,g,f===l.$$state?null:l.$$state),k(a,f)))});l.$$replace=!1});return l}]}function rf(){var a=!0,b=this;this.debugEnabled=function(b){return x(b)?(a=b,this):a};this.$get=["$window",function(d){function c(a){a instanceof Error&&(a.stack?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;a=!1;try{a=!!e.apply}catch(k){}return a?function(){var a=[];q(arguments,function(b){a.push(c(b))});return e.apply(b,a)}:function(a,b){e(a,null==b?"":b)}}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 Ta(a,b){if("__defineGetter__"===a||"__defineSetter__"===a||"__lookupGetter__"===a||"__lookupSetter__"=== +a||"__proto__"===a)throw ca("isecfld",b);return a}function fg(a){return a+""}function sa(a,b){if(a){if(a.constructor===a)throw ca("isecfn",b);if(a.window===a)throw ca("isecwindow",b);if(a.children&&(a.nodeName||a.prop&&a.attr&&a.find))throw ca("isecdom",b);if(a===Object)throw ca("isecobj",b);}return a}function md(a,b){if(a){if(a.constructor===a)throw ca("isecfn",b);if(a===gg||a===hg||a===ig)throw ca("isecff",b);}}function Gb(a,b){if(a&&(a===(0).constructor||a===(!1).constructor||a==="".constructor|| +a==={}.constructor||a===[].constructor||a===Function.constructor))throw ca("isecaf",b);}function jg(a,b){return"undefined"!==typeof a?a:b}function nd(a,b){return"undefined"===typeof a?b:"undefined"===typeof b?a:a+b}function aa(a,b){var d,c;switch(a.type){case s.Program:d=!0;q(a.body,function(a){aa(a.expression,b);d=d&&a.expression.constant});a.constant=d;break;case s.Literal:a.constant=!0;a.toWatch=[];break;case s.UnaryExpression:aa(a.argument,b);a.constant=a.argument.constant;a.toWatch=a.argument.toWatch; +break;case s.BinaryExpression:aa(a.left,b);aa(a.right,b);a.constant=a.left.constant&&a.right.constant;a.toWatch=a.left.toWatch.concat(a.right.toWatch);break;case s.LogicalExpression:aa(a.left,b);aa(a.right,b);a.constant=a.left.constant&&a.right.constant;a.toWatch=a.constant?[]:[a];break;case s.ConditionalExpression:aa(a.test,b);aa(a.alternate,b);aa(a.consequent,b);a.constant=a.test.constant&&a.alternate.constant&&a.consequent.constant;a.toWatch=a.constant?[]:[a];break;case s.Identifier:a.constant= +!1;a.toWatch=[a];break;case s.MemberExpression:aa(a.object,b);a.computed&&aa(a.property,b);a.constant=a.object.constant&&(!a.computed||a.property.constant);a.toWatch=[a];break;case s.CallExpression:d=a.filter?!b(a.callee.name).$stateful:!1;c=[];q(a.arguments,function(a){aa(a,b);d=d&&a.constant;a.constant||c.push.apply(c,a.toWatch)});a.constant=d;a.toWatch=a.filter&&!b(a.callee.name).$stateful?c:[a];break;case s.AssignmentExpression:aa(a.left,b);aa(a.right,b);a.constant=a.left.constant&&a.right.constant; +a.toWatch=[a];break;case s.ArrayExpression:d=!0;c=[];q(a.elements,function(a){aa(a,b);d=d&&a.constant;a.constant||c.push.apply(c,a.toWatch)});a.constant=d;a.toWatch=c;break;case s.ObjectExpression:d=!0;c=[];q(a.properties,function(a){aa(a.value,b);d=d&&a.value.constant;a.value.constant||c.push.apply(c,a.value.toWatch)});a.constant=d;a.toWatch=c;break;case s.ThisExpression:a.constant=!1;a.toWatch=[];break;case s.LocalsExpression:a.constant=!1,a.toWatch=[]}}function od(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 pd(a){return a.type===s.Identifier||a.type===s.MemberExpression}function qd(a){if(1===a.body.length&&pd(a.body[0].expression))return{type:s.AssignmentExpression,left:a.body[0].expression,right:{type:s.NGValueParameter},operator:"="}}function rd(a){return 0===a.body.length||1===a.body.length&&(a.body[0].expression.type===s.Literal||a.body[0].expression.type===s.ArrayExpression||a.body[0].expression.type===s.ObjectExpression)}function sd(a, +b){this.astBuilder=a;this.$filter=b}function td(a,b){this.astBuilder=a;this.$filter=b}function Hb(a){return"constructor"==a}function fc(a){return E(a.valueOf)?a.valueOf():kg.call(a)}function sf(){var a=T(),b=T(),d={"true":!0,"false":!1,"null":null,undefined:void 0},c,e;this.addLiteral=function(a,b){d[a]=b};this.setIdentifierFns=function(a,b){c=a;e=b;return this};this.$get=["$filter",function(f){function g(c,d,e){var g,k,D;e=e||H;switch(typeof c){case "string":D=c=c.trim();var q=e?b:a;g=q[D];if(!g){":"=== +c.charAt(0)&&":"===c.charAt(1)&&(k=!0,c=c.substring(2));g=e?p:w;var S=new gc(g);g=(new hc(S,f,g)).parse(c);g.constant?g.$$watchDelegate=r:k?g.$$watchDelegate=g.literal?m:n:g.inputs&&(g.$$watchDelegate=l);e&&(g=h(g));q[D]=g}return N(g,d);case "function":return N(c,d);default:return N(C,d)}}function h(a){function b(c,d,e,f){var g=H;H=!0;try{return a(c,d,e,f)}finally{H=g}}if(!a)return a;b.$$watchDelegate=a.$$watchDelegate;b.assign=h(a.assign);b.constant=a.constant;b.literal=a.literal;for(var c=0;a.inputs&& +c=this.promise.$$state.status&&d&&d.length&&a(function(){for(var a,e,f=0,g=d.length;f +a)for(b in l++,f)ua.call(e,b)||(t--,delete f[b])}else f!==e&&(f=e,l++);return l}}c.$stateful=!0;var d=this,e,f,h,k=1N&&(y=4-N,x[y]||(x[y]=[]),x[y].push({msg:E(a.exp)?"fn: "+(a.exp.name||a.exp.toString()):a.exp,newVal:g,oldVal:k}));else if(a===c){q=!1;break a}}catch(F){f(F)}if(!(r=u.$$watchersCount&& +u.$$childHead||u!==this&&u.$$nextSibling))for(;u!==this&&!(r=u.$$nextSibling);)u=u.$parent}while(u=r);if((q||t.length)&&!N--)throw H.$$phase=null,d("infdig",b,x);}while(q||t.length);for(H.$$phase=null;z.length;)try{z.shift()()}catch(B){f(B)}},$destroy:function(){if(!this.$$destroyed){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;this===H&&h.$$applicationDestroyed();r(this,-this.$$watchersCount);for(var b in this.$$listenerCount)N(this,this.$$listenerCount[b],b);a&&a.$$childHead== +this&&(a.$$childHead=this.$$nextSibling);a&&a.$$childTail==this&&(a.$$childTail=this.$$prevSibling);this.$$prevSibling&&(this.$$prevSibling.$$nextSibling=this.$$nextSibling);this.$$nextSibling&&(this.$$nextSibling.$$prevSibling=this.$$prevSibling);this.$destroy=this.$digest=this.$apply=this.$evalAsync=this.$applyAsync=C;this.$on=this.$watch=this.$watchGroup=function(){return C};this.$$listeners={};this.$$nextSibling=null;l(this)}},$eval:function(a,b){return g(a)(this,b)},$evalAsync:function(a,b){H.$$phase|| +t.length||h.defer(function(){t.length&&H.$digest()});t.push({scope:this,expression:g(a),locals:b})},$$postDigest:function(a){z.push(a)},$apply:function(a){try{m("$apply");try{return this.$eval(a)}finally{H.$$phase=null}}catch(b){f(b)}finally{try{H.$digest()}catch(c){throw f(c),c;}}},$applyAsync:function(a){function b(){c.$eval(a)}var c=this;a&&u.push(b);a=g(a);p()},$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=c=[]);c.push(b);var d=this;do d.$$listenerCount[a]||(d.$$listenerCount[a]= +0),d.$$listenerCount[a]++;while(d=d.$parent);var e=this;return function(){var d=c.indexOf(b);-1!==d&&(c[d]=null,N(e,1,a))}},$emit:function(a,b){var c=[],d,e=this,g=!1,h={name:a,targetScope:e,stopPropagation:function(){g=!0},preventDefault:function(){h.defaultPrevented=!0},defaultPrevented:!1},k=$a([h],arguments,1),l,n;do{d=e.$$listeners[a]||c;h.currentScope=e;l=0;for(n=d.length;lCa)throw ta("iequirks");var c=ha(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=Xa);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;q(oa,function(a,b){var d=P(b);c[cb("parse_as_"+d)]=function(b){return e(a,b)};c[cb("get_trusted_"+d)]=function(b){return f(a,b)};c[cb("trust_as_"+d)]=function(b){return g(a,b)}});return c}]}function yf(){this.$get=["$window","$document",function(a,b){var d={},c=!(a.chrome&&a.chrome.app&&a.chrome.app.runtime)&&a.history&&a.history.pushState, +e=X((/android (\d+)/.exec(P((a.navigator||{}).userAgent))||[])[1]),f=/Boxee/i.test((a.navigator||{}).userAgent),g=b[0]||{},h,k=/^(Moz|webkit|ms)(?=[A-Z])/,l=g.body&&g.body.style,n=!1,m=!1;if(l){for(var r in l)if(n=k.exec(r)){h=n[0];h=h.substr(0,1).toUpperCase()+h.substr(1);break}h||(h="WebkitOpacity"in l&&"webkit");n=!!("transition"in l||h+"Transition"in l);m=!!("animation"in l||h+"Animation"in l);!e||n&&m||(n=F(l.webkitTransition),m=F(l.webkitAnimation))}return{history:!(!c||4>e||f),hasEvent:function(a){if("input"=== +a&&11>=Ca)return!1;if(y(d[a])){var b=g.createElement("div");d[a]="on"+a in b}return d[a]},csp:Ea(),vendorPrefix:h,transitions:n,animations:m,android:e}}]}function Af(){var a;this.httpOptions=function(b){return b?(a=b,this):a};this.$get=["$templateCache","$http","$q","$sce",function(b,d,c,e){function f(g,h){f.totalPendingRequests++;F(g)&&b.get(g)||(g=e.getTrustedResourceUrl(g));var k=d.defaults&&d.defaults.transformResponse;K(k)?k=k.filter(function(a){return a!==ac}):k===ac&&(k=null);return d.get(g, +R({cache:b,transformResponse:k},a))["finally"](function(){f.totalPendingRequests--}).then(function(a){b.put(g,a.data);return a.data},function(a){if(!h)throw mg("tpload",g,a.status,a.statusText);return c.reject(a)})}f.totalPendingRequests=0;return f}]}function Bf(){this.$get=["$rootScope","$browser","$location",function(a,b,d){return{findBindings:function(a,b,d){a=a.getElementsByClassName("ng-binding");var g=[];q(a,function(a){var c=ea.element(a).data("$binding");c&&q(c,function(c){d?(new RegExp("(^|\\s)"+ +vd(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\\:"],h=0;hc&&(c=e),c+=+a.slice(e+1),a=a.substring(0,e)):0>c&&(c=a.length);for(e=0;a.charAt(e)==jc;e++);if(e==(g=a.length))d=[0],c=1;else{for(g--;a.charAt(g)==jc;)g--;c-=e;d=[];for(f=0;e<=g;e++,f++)d[f]=+a.charAt(e)}c>Fd&&(d=d.splice(0,Fd-1),b=c-1,c=1);return{d:d,e:b,i:c}}function ug(a,b,d,c){var e=a.d,f=e.length-a.i;b=y(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(;fh;)k.unshift(0),h++;0=b.lgSize&&h.unshift(k.splice(-b.lgSize).join(""));k.length>b.gSize;)h.unshift(k.splice(-b.gSize).join(""));k.length&&h.unshift(k.join(""));k=h.join(d);f.length&&(k+=c+f.join(""));e&&(k+="e+"+e)}return 0>a&&!g?b.negPre+k+b.negSuf:b.posPre+k+b.posSuf}function Ib(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 Ib(f,b,c,e)}}function ib(a,b,d){return function(c,e){var f=c["get"+a](),g=sb((d?"STANDALONE":"")+(b?"SHORT":"")+a);return e[g][f]}}function Gd(a){var b=(new Date(a,0,1)).getDay();return new Date(a,0,(4>=b?5:12)-b)}function Hd(a){return function(b){var d=Gd(b.getFullYear());b=+new Date(b.getFullYear(),b.getMonth(),b.getDate()+(4-b.getDay()))-+d;b=1+Math.round(b/6048E5);return Ib(b,a)}}function kc(a,b){return 0>=a.getFullYear()? +b.ERAS[0]:b.ERAS[1]}function Ad(a){function b(a){var b;if(b=a.match(d)){a=new Date(0);var f=0,g=0,h=b[8]?a.setUTCFullYear:a.setFullYear,k=b[8]?a.setUTCHours:a.setHours;b[9]&&(f=X(b[9]+b[10]),g=X(b[9]+b[11]));h.call(a,X(b[1]),X(b[2])-1,X(b[3]));f=X(b[4]||0)-f;g=X(b[5]||0)-g;h=X(b[6]||0);b=Math.round(1E3*parseFloat("0."+(b[7]||0)));k.call(a,f,g,h,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="",h= +[],k,l;d=d||"mediumDate";d=a.DATETIME_FORMATS[d]||d;F(c)&&(c=vg.test(c)?X(c):b(c));Q(c)&&(c=new Date(c));if(!fa(c)||!isFinite(c.getTime()))return c;for(;d;)(l=wg.exec(d))?(h=$a(h,l,1),d=h.pop()):(h.push(d),d=null);var n=c.getTimezoneOffset();f&&(n=vc(f,n),c=Qb(c,f,!0));q(h,function(b){k=xg[b];g+=k?k(c,a.DATETIME_FORMATS,n):"''"===b?"'":b.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function og(){return function(a,b){y(b)&&(b=2);return ab(a,b)}}function pg(){return function(a,b,d){b=Infinity=== +Math.abs(Number(b))?Number(b):X(b);if(isNaN(b))return a;Q(a)&&(a=a.toString());if(!K(a)&&!F(a))return a;d=!d||isNaN(d)?0:X(d);d=0>d?Math.max(0,a.length+d):d;return 0<=b?a.slice(d,d+b):0===d?a.slice(b,a.length):a.slice(Math.max(0,d+b),d)}}function Cd(a){function b(b,d){d=d?-1:1;return b.map(function(b){var c=1,h=Xa;if(E(b))h=b;else if(F(b)){if("+"==b.charAt(0)||"-"==b.charAt(0))c="-"==b.charAt(0)?-1:1,b=b.substring(1);if(""!==b&&(h=a(b),h.constant))var k=h(),h=function(a){return a[k]}}return{get:h, +descending:c*d}})}function d(a){switch(typeof a){case "number":case "boolean":case "string":return!0;default:return!1}}return function(a,e,f){if(null==a)return a;if(!ya(a))throw O("orderBy")("notarray",a);K(e)||(e=[e]);0===e.length&&(e=["+"]);var g=b(e,f);g.push({get:function(){return{}},descending:f?-1:1});a=Array.prototype.map.call(a,function(a,b){return{value:a,predicateValues:g.map(function(c){var e=c.get(a);c=typeof e;if(null===e)c="string",e="null";else if("string"===c)e=e.toLowerCase();else if("object"=== +c)a:{if("function"===typeof e.valueOf&&(e=e.valueOf(),d(e)))break a;if(rc(e)&&(e=e.toString(),d(e)))break a;e=b}return{value:e,type:c}})}});a.sort(function(a,b){for(var c=0,d=0,e=g.length;db||37<=b&&40>=b||n(a,this,this.value)});if(e.hasEvent("paste"))b.on("paste cut",n)}b.on("change",l);if(Kd[g]&&c.$$hasNativeValidators&&g===d.type)b.on("keydown wheel mousedown",function(a){if(!k){var b=this.validity,c=b.badInput,d=b.typeMismatch;k=f.defer(function(){k=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 Lb(a,b){return function(d,c){var e,f;if(fa(d))return d;if(F(d)){'"'==d.charAt(0)&& +'"'==d.charAt(d.length-1)&&(d=d.substring(1,d.length-1));if(yg.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},q(e,function(a,c){c= +w};g.$observe("min",function(a){w=r(a);h.$validate()})}if(x(g.max)||g.ngMax){var p;h.$validators.max=function(a){return!m(a)||y(p)||d(a)<=p};g.$observe("max",function(a){p=r(a);h.$validate()})}}}function Ld(a,b,d,c){(c.$$hasNativeValidators=G(b[0].validity))&&c.$parsers.push(function(a){var c=b.prop("validity")||{};return c.badInput||c.typeMismatch?void 0:a})}function Md(a,b,d,c,e){if(x(c)){a=a(c);if(!a.constant)throw lb("constexpr",d,c);return a(b)}return e}function mc(a,b){a="ngClass"+a;return["$animate", +function(d){function c(a,b){var c=[],d=0;a:for(;d(?:<\/\1>|)$/,Tb=/<|&#?\w+;/,Kf=/<([\w:-]+)/,Lf=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi, +ia={option:[1,'"],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ia.optgroup=ia.option;ia.tbody=ia.tfoot=ia.colgroup=ia.caption=ia.thead;ia.th=ia.td;var Sf=v.Node.prototype.contains||function(a){return!!(this.compareDocumentPosition(a)&16)},Oa=U.prototype={ready:function(a){function b(){d||(d=!0,a())}var d=!1;"complete"=== +v.document.readyState?v.setTimeout(b):(this.on("DOMContentLoaded",b),U(v).on("load",b))},toString:function(){var a=[];q(this,function(b){a.push(""+b)});return"["+a.join(", ")+"]"},eq:function(a){return 0<=a?B(this[a]):B(this[this.length+a])},length:0,push:Ag,sort:[].sort,splice:[].splice},Cb={};q("multiple selected checked disabled readOnly required open".split(" "),function(a){Cb[P(a)]=a});var Sc={};q("input select option textarea button form details".split(" "),function(a){Sc[a]=!0});var ad={ngMinlength:"minlength", +ngMaxlength:"maxlength",ngMin:"min",ngMax:"max",ngPattern:"pattern"};q({data:Wb,removeData:db,hasData:function(a){for(var b in eb[a.ng339])return!0;return!1},cleanData:function(a){for(var b=0,d=a.length;b/,Vf=/^[^\(]*\(\s*([^\)]*)\)/m,Bg=/,/,Cg=/^\s*(_?)(\S+?)\1\s*$/,Tf=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,Ga=O("$injector");bb.$$annotate=function(a,b,d){var c;if("function"===typeof a){if(!(c=a.$inject)){c=[];if(a.length){if(b)throw F(d)&&d||(d=a.name||Wf(a)),Ga("strictdi",d); +b=Tc(a);q(b[1].split(Bg),function(a){a.replace(Cg,function(a,b,d){c.push(d)})})}a.$inject=c}}else K(a)?(b=a.length-1,Pa(a[b],"fn"),c=a.slice(0,b)):Pa(a,"fn",!0);return c};var Qd=O("$animate"),Ze=function(){this.$get=C},$e=function(){var a=new Ra,b=[];this.$get=["$$AnimateRunner","$rootScope",function(d,c){function e(a,b,c){var d=!1;b&&(b=F(b)?b.split(" "):K(b)?b:[],q(b,function(b){b&&(d=!0,a[b]=c)}));return d}function f(){q(b,function(b){var c=a.get(b);if(c){var d=Xf(b.attr("class")),e="",f="";q(c, +function(a,b){a!==!!d[b]&&(a?e+=(e.length?" ":"")+b:f+=(f.length?" ":"")+b)});q(b,function(a){e&&zb(a,e);f&&yb(a,f)});a.remove(b)}});b.length=0}return{enabled:C,on:C,off:C,pin:C,push:function(g,h,k,l){l&&l();k=k||{};k.from&&g.css(k.from);k.to&&g.css(k.to);if(k.addClass||k.removeClass)if(h=k.addClass,l=k.removeClass,k=a.get(g)||{},h=e(k,h,!0),l=e(k,l,!1),h||l)a.put(g,k),b.push(g),1===b.length&&c.$$postDigest(f);g=new d;g.complete();return g}}}]},Xe=["$provide",function(a){var b=this;this.$$registeredAnimations= +Object.create(null);this.register=function(d,c){if(d&&"."!==d.charAt(0))throw Qd("notcsel",d);var e=d+"-animation";b.$$registeredAnimations[d.substr(1)]=e;a.factory(e,c)};this.classNameFilter=function(a){if(1===arguments.length&&(this.$$classNameFilter=a instanceof RegExp?a:null)&&/(\s+|\/)ng-animate(\s+|\/)/.test(this.$$classNameFilter.toString()))throw Qd("nongcls","ng-animate");return this.$$classNameFilter};this.$get=["$$animateQueue",function(a){function b(a,c,d){if(d){var h;a:{for(h=0;h <= >= && || ! = |".split(" "),function(a){Mb[a]=!0});var Gg={n:"\n",f:"\f",r:"\r", +t:"\t",v:"\v","'":"'",'"':'"'},gc=function(a){this.options=a};gc.prototype={constructor:gc,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=x(b)?"s "+b+"-"+this.index+" ["+this.text.substring(b,d)+"]":" "+d;throw ca("lexerr", +a,b,this.text);},readNumber:function(){for(var a="",b=this.index;this.index","<=",">=");)a={type:s.BinaryExpression,operator:b.text,left:a,right:this.additive()};return a},additive:function(){for(var a=this.multiplicative(), +b;b=this.expect("+","-");)a={type:s.BinaryExpression,operator:b.text,left:a,right:this.multiplicative()};return a},multiplicative:function(){for(var a=this.unary(),b;b=this.expect("*","/","%");)a={type:s.BinaryExpression,operator:b.text,left:a,right:this.unary()};return a},unary:function(){var a;return(a=this.expect("+","-","!"))?{type:s.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=qa(this.selfReferential[this.consume().text]):this.options.literals.hasOwnProperty(this.peek().text)?a={type:s.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:s.CallExpression, +callee:a,arguments:this.parseArguments()},this.consume(")")):"["===b.text?(a={type:s.MemberExpression,object:a,property:this.expression(),computed:!0},this.consume("]")):"."===b.text?a={type:s.MemberExpression,object:a,property:this.identifier(),computed:!1}:this.throwError("IMPOSSIBLE");return a},filter:function(a){a=[a];for(var b={type:s.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.expression());while(this.expect(","))}return a},identifier:function(){var a=this.consume();a.identifier||this.throwError("is not a valid identifier",a);return{type:s.Identifier,name:a.text}},constant:function(){return{type:s.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:s.ArrayExpression,elements:a}}, +object:function(){var a=[],b;if("}"!==this.peekToken().text){do{if(this.peek("}"))break;b={type:s.Property,kind:"init"};this.peek().constant?b.key=this.constant():this.peek().identifier?b.key=this.identifier():this.throwError("invalid key",this.peek());this.consume(":");b.value=this.expression();a.push(b)}while(this.expect(","))}this.consume("}");return{type:s.ObjectExpression,properties:a}},throwError:function(a,b){throw ca("syntax",b.text,a,b.index+1,this.text,this.text.substring(b.index));},consume:function(a){if(0=== +this.tokens.length)throw ca("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 ca("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:s.ThisExpression},$locals:{type:s.LocalsExpression}}};sd.prototype={compile:function(a,b){var d=this,c=this.astBuilder.ast(a);this.state={nextId:0,filters:{},expensiveChecks:b,fn:{vars:[],body:[],own:{}},assign:{vars:[],body:[],own:{}},inputs:[]};aa(c,d.$filter);var e="",f;this.stage="assign";if(f=qd(c))this.state.computing="assign",e=this.nextId(),this.recurse(f,e),this.return_(e),e="fn.assign="+this.generateFunction("assign","s,v,l");f=od(c.body); +d.stage="inputs";q(f,function(a,b){var c="fn"+b;d.state[c]={vars:[],body:[],own:{}};d.state.computing=c;var e=d.nextId();d.recurse(a,e);d.return_(e);d.state.inputs.push(c);a.watchId=b});this.state.computing="fn";this.stage="main";this.recurse(c);e='"'+this.USE+" "+this.STRICT+'";\n'+this.filterPrefix()+"var fn="+this.generateFunction("fn","s,l,a,i")+e+this.watchFns()+"return fn;";e=(new Function("$filter","ensureSafeMemberName","ensureSafeObject","ensureSafeFunction","getStringValue","ensureSafeAssignContext", +"ifDefined","plus","text",e))(this.$filter,Ta,sa,md,fg,Gb,jg,nd,a);this.state=this.stage=void 0;e.literal=rd(c);e.constant=c.constant;return e},USE:"use",STRICT:"strict",watchFns:function(){var a=[],b=this.state.inputs,d=this;q(b,function(b){a.push("var "+b+"="+d.generateFunction(b,"s"))});b.length&&a.push("fn.inputs=["+b.join(",")+"];");return a.join("")},generateFunction:function(a,b){return"function("+b+"){"+this.varsPrefix(a)+this.body(a)+"};"},filterPrefix:function(){var a=[],b=this;q(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,h,k=this,l,n;c=c||C;if(!f&&x(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 s.Program:q(a.body,function(b,c){k.recurse(b.expression, +void 0,void 0,function(a){h=a});c!==a.body.length-1?k.current().body.push(h,";"):k.return_(h)});break;case s.Literal:n=this.escape(a.value);this.assign(b,n);c(n);break;case s.UnaryExpression:this.recurse(a.argument,void 0,void 0,function(a){h=a});n=a.operator+"("+this.ifDefined(h,0)+")";this.assign(b,n);c(n);break;case s.BinaryExpression:this.recurse(a.left,void 0,void 0,function(a){g=a});this.recurse(a.right,void 0,void 0,function(a){h=a});n="+"===a.operator?this.plus(g,h):"-"===a.operator?this.ifDefined(g, +0)+a.operator+this.ifDefined(h,0):"("+g+")"+a.operator+"("+h+")";this.assign(b,n);c(n);break;case s.LogicalExpression:b=b||this.nextId();k.recurse(a.left,b);k.if_("&&"===a.operator?b:k.not(b),k.lazyRecurse(a.right,b));c(b);break;case s.ConditionalExpression:b=b||this.nextId();k.recurse(a.test,b);k.if_(b,k.lazyRecurse(a.alternate,b),k.lazyRecurse(a.consequent,b));c(b);break;case s.Identifier:b=b||this.nextId();d&&(d.context="inputs"===k.stage?"s":this.assign(this.nextId(),this.getHasOwnProperty("l", +a.name)+"?l:s"),d.computed=!1,d.name=a.name);Ta(a.name);k.if_("inputs"===k.stage||k.not(k.getHasOwnProperty("l",a.name)),function(){k.if_("inputs"===k.stage||"s",function(){e&&1!==e&&k.if_(k.not(k.nonComputedMember("s",a.name)),k.lazyAssign(k.nonComputedMember("s",a.name),"{}"));k.assign(b,k.nonComputedMember("s",a.name))})},b&&k.lazyAssign(b,k.nonComputedMember("l",a.name)));(k.state.expensiveChecks||Hb(a.name))&&k.addEnsureSafeObject(b);c(b);break;case s.MemberExpression:g=d&&(d.context=this.nextId())|| +this.nextId();b=b||this.nextId();k.recurse(a.object,g,void 0,function(){k.if_(k.notNull(g),function(){e&&1!==e&&k.addEnsureSafeAssignContext(g);if(a.computed)h=k.nextId(),k.recurse(a.property,h),k.getStringValue(h),k.addEnsureSafeMemberName(h),e&&1!==e&&k.if_(k.not(k.computedMember(g,h)),k.lazyAssign(k.computedMember(g,h),"{}")),n=k.ensureSafeObject(k.computedMember(g,h)),k.assign(b,n),d&&(d.computed=!0,d.name=h);else{Ta(a.property.name);e&&1!==e&&k.if_(k.not(k.nonComputedMember(g,a.property.name)), +k.lazyAssign(k.nonComputedMember(g,a.property.name),"{}"));n=k.nonComputedMember(g,a.property.name);if(k.state.expensiveChecks||Hb(a.property.name))n=k.ensureSafeObject(n);k.assign(b,n);d&&(d.computed=!1,d.name=a.property.name)}},function(){k.assign(b,"undefined")});c(b)},!!e);break;case s.CallExpression:b=b||this.nextId();a.filter?(h=k.filter(a.callee.name),l=[],q(a.arguments,function(a){var b=k.nextId();k.recurse(a,b);l.push(b)}),n=h+"("+l.join(",")+")",k.assign(b,n),c(b)):(h=k.nextId(),g={},l= +[],k.recurse(a.callee,h,g,function(){k.if_(k.notNull(h),function(){k.addEnsureSafeFunction(h);q(a.arguments,function(a){k.recurse(a,k.nextId(),void 0,function(a){l.push(k.ensureSafeObject(a))})});g.name?(k.state.expensiveChecks||k.addEnsureSafeObject(g.context),n=k.member(g.context,g.name,g.computed)+"("+l.join(",")+")"):n=h+"("+l.join(",")+")";n=k.ensureSafeObject(n);k.assign(b,n)},function(){k.assign(b,"undefined")});c(b)}));break;case s.AssignmentExpression:h=this.nextId();g={};if(!pd(a.left))throw ca("lval"); +this.recurse(a.left,void 0,g,function(){k.if_(k.notNull(g.context),function(){k.recurse(a.right,h);k.addEnsureSafeObject(k.member(g.context,g.name,g.computed));k.addEnsureSafeAssignContext(g.context);n=k.member(g.context,g.name,g.computed)+a.operator+h;k.assign(b,n);c(b||n)})},1);break;case s.ArrayExpression:l=[];q(a.elements,function(a){k.recurse(a,k.nextId(),void 0,function(a){l.push(a)})});n="["+l.join(",")+"]";this.assign(b,n);c(n);break;case s.ObjectExpression:l=[];q(a.properties,function(a){k.recurse(a.value, +k.nextId(),void 0,function(b){l.push(k.escape(a.key.type===s.Identifier?a.key.name:""+a.key.value)+":"+b)})});n="{"+l.join(",")+"}";this.assign(b,n);c(n);break;case s.ThisExpression:this.assign(b,"s");c("s");break;case s.LocalsExpression:this.assign(b,"l");c("l");break;case s.NGValueParameter:this.assign(b,"v"),c("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+")"},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)},addEnsureSafeObject:function(a){this.current().body.push(this.ensureSafeObject(a),";")},addEnsureSafeMemberName:function(a){this.current().body.push(this.ensureSafeMemberName(a),";")},addEnsureSafeFunction:function(a){this.current().body.push(this.ensureSafeFunction(a), +";")},addEnsureSafeAssignContext:function(a){this.current().body.push(this.ensureSafeAssignContext(a),";")},ensureSafeObject:function(a){return"ensureSafeObject("+a+",text)"},ensureSafeMemberName:function(a){return"ensureSafeMemberName("+a+",text)"},ensureSafeFunction:function(a){return"ensureSafeFunction("+a+",text)"},getStringValue:function(a){this.assign(a,"getStringValue("+a+")")},ensureSafeAssignContext:function(a){return"ensureSafeAssignContext("+a+",text)"},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(F(a))return"'"+a.replace(this.stringEscapeRegex,this.stringEscapeFn)+"'";if(Q(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 ca("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]}};td.prototype={compile:function(a,b){var d=this,c=this.astBuilder.ast(a);this.expression=a;this.expensiveChecks=b;aa(c,d.$filter);var e,f;if(e=qd(c))f=this.recurse(e);e=od(c.body);var g;e&&(g=[],q(e,function(a,b){var c=d.recurse(a);a.input=c;g.push(c);a.watchId=b}));var h=[];q(c.body,function(a){h.push(d.recurse(a.expression))});e=0===c.body.length?C:1=== +c.body.length?h[0]:function(a,b){var c;q(h,function(d){c=d(a,b)});return c};f&&(e.assign=function(a,b,c){return f(a,c,b)});g&&(e.inputs=g);e.literal=rd(c);e.constant=c.constant;return e},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 s.Literal:return this.value(a.value,b);case s.UnaryExpression:return e=this.recurse(a.argument),this["unary"+a.operator](e,b);case s.BinaryExpression:return c=this.recurse(a.left),e=this.recurse(a.right), +this["binary"+a.operator](c,e,b);case s.LogicalExpression:return c=this.recurse(a.left),e=this.recurse(a.right),this["binary"+a.operator](c,e,b);case s.ConditionalExpression:return this["ternary?:"](this.recurse(a.test),this.recurse(a.alternate),this.recurse(a.consequent),b);case s.Identifier:return Ta(a.name,f.expression),f.identifier(a.name,f.expensiveChecks||Hb(a.name),b,d,f.expression);case s.MemberExpression:return c=this.recurse(a.object,!1,!!d),a.computed||(Ta(a.property.name,f.expression), +e=a.property.name),a.computed&&(e=this.recurse(a.property)),a.computed?this.computedMember(c,e,b,d,f.expression):this.nonComputedMember(c,e,f.expensiveChecks,b,d,f.expression);case s.CallExpression:return g=[],q(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 m=[],r=0;r":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,h){e=a(e,f,g,h)?b(e,f,g,h):d(e,f,g,h);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,c,e){return function(f,g,h,k){f=g&&a in g?g:f;c&&1!==c&&f&&!f[a]&&(f[a]={});g=f?f[a]:void 0;b&&sa(g,e);return d?{context:f,name:a,value:g}:g}},computedMember:function(a,b,d,c,e){return function(f,g,h,k){var l=a(f,g,h,k),n,m;null!=l&&(n=b(f,g,h,k),n+="",Ta(n,e),c&&1!==c&&(Gb(l),l&&!l[n]&&(l[n]={})),m=l[n],sa(m,e));return d?{context:l,name:n,value:m}:m}},nonComputedMember:function(a,b,d,c,e,f){return function(g,h,k,l){g=a(g,h,k,l);e&&1!==e&&(Gb(g), +g&&!g[b]&&(g[b]={}));h=null!=g?g[b]:void 0;(d||Hb(b))&&sa(h,f);return c?{context:g,name:b,value:h}:h}},inputs:function(a,b){return function(d,c,e,f){return f?f[b]:a(d,c,e)}}};var hc=function(a,b,d){this.lexer=a;this.$filter=b;this.options=d;this.ast=new s(a,d);this.astCompiler=d.csp?new td(this.ast,b):new sd(this.ast,b)};hc.prototype={constructor:hc,parse:function(a){return this.astCompiler.compile(a,this.options.expensiveChecks)}};var kg=Object.prototype.valueOf,ta=O("$sce"),oa={HTML:"html",CSS:"css", +URL:"url",RESOURCE_URL:"resourceUrl",JS:"js"},mg=O("$compile"),Y=v.document.createElement("a"),xd=ra(v.location.href);yd.$inject=["$document"];Jc.$inject=["$provide"];var Fd=22,Ed=".",jc="0";zd.$inject=["$locale"];Bd.$inject=["$locale"];var xg={yyyy:W("FullYear",4,0,!1,!0),yy:W("FullYear",2,0,!0,!0),y:W("FullYear",1,0,!1,!0),MMMM:ib("Month"),MMM:ib("Month",!0),MM:W("Month",2,1),M:W("Month",1,1),LLLL:ib("Month",!1,!0),dd:W("Date",2),d:W("Date",1),HH:W("Hours",2),H:W("Hours",1),hh:W("Hours",2,-12), +h:W("Hours",1,-12),mm:W("Minutes",2),m:W("Minutes",1),ss:W("Seconds",2),s:W("Seconds",1),sss:W("Milliseconds",3),EEEE:ib("Day"),EEE:ib("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?"+":"")+(Ib(Math[0=a.getFullYear()?b.ERANAMES[0]:b.ERANAMES[1]}},wg=/((?:[^yMLdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/, +vg=/^\-?\d+$/;Ad.$inject=["$locale"];var qg=da(P),rg=da(sb);Cd.$inject=["$parse"];var ne=da({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()})}}}}),tb={};q(Cb,function(a,b){function d(a,d,e){a.$watch(e[c],function(a){e.$set(b,!!a)})}if("multiple"!=a){var c=xa("ng-"+b),e=d;"checked"===a&&(e=function(a, +b,e){e.ngModel!==e[c]&&d(a,b,e)});tb[c]=function(){return{restrict:"A",priority:100,link:e}}}});q(ad,function(a,b){tb[b]=function(){return{priority:100,link:function(a,c,e){if("ngPattern"===b&&"/"==e.ngPattern.charAt(0)&&(c=e.ngPattern.match(zg))){e.$set("ngPattern",new RegExp(c[1],c[2]));return}a.$watch(e[b],function(a){e.$set(b,a)})}}}});q(["src","srcset","href"],function(a){var b=xa("ng-"+a);tb[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),Ca&&f&&c.prop(f,e[g])):"href"===a&&e.$set(g,null)})}}}});var Jb={$addControl:C,$$renameControl:function(a,b){a.$name=b},$removeControl:C,$setValidity:C,$setDirty:C,$setPristine:C,$setSubmitted:C};Id.$inject=["$element","$attrs","$scope","$animate","$interpolate"];var Rd=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:Id,compile:function(d,f){d.addClass(Ua).addClass(mb);var g=f.name?"name":a&&f.ngForm?"ngForm":!1;return{pre:function(a,d,e,f){var m=f[0];if(!("action"in e)){var r=function(b){a.$apply(function(){m.$commitViewValue();m.$setSubmitted()});b.preventDefault()};d[0].addEventListener("submit",r,!1);d.on("$destroy",function(){b(function(){d[0].removeEventListener("submit",r,!1)},0,!1)})}(f[1]||m.$$parentForm).$addControl(m);var q=g?c(m.$name):C;g&& +(q(a,m),e.$observe(g,function(b){m.$name!==b&&(q(a,void 0),m.$$parentForm.$$renameControl(m,b),q=c(m.$name),q(a,m))}));d.on("$destroy",function(){m.$$parentForm.$removeControl(m);q(a,void 0);R(m,Jb)})}}}}}]},oe=Rd(),Be=Rd(!0),yg=/^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-][0-2]\d:[0-5]\d|Z)$/,Hg=/^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i,Ig=/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i, +Jg=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/,Sd=/^(\d{4,})-(\d{2})-(\d{2})$/,Td=/^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,nc=/^(\d{4,})-W(\d\d)$/,Ud=/^(\d{4,})-(\d\d)$/,Vd=/^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,Kd=T();q(["date","datetime-local","month","time","week"],function(a){Kd[a]=!0});var Wd={text:function(a,b,d,c,e,f){jb(a,b,d,c,e,f);lc(c)},date:kb("date",Sd,Lb(Sd,["yyyy","MM","dd"]),"yyyy-MM-dd"),"datetime-local":kb("datetimelocal",Td,Lb(Td,"yyyy MM dd HH mm ss sss".split(" ")), +"yyyy-MM-ddTHH:mm:ss.sss"),time:kb("time",Vd,Lb(Vd,["HH","mm","ss","sss"]),"HH:mm:ss.sss"),week:kb("week",nc,function(a,b){if(fa(a))return a;if(F(a)){nc.lastIndex=0;var d=nc.exec(a);if(d){var c=+d[1],e=+d[2],f=d=0,g=0,h=0,k=Gd(c),e=7*(e-1);b&&(d=b.getHours(),f=b.getMinutes(),g=b.getSeconds(),h=b.getMilliseconds());return new Date(c,0,k.getDate()+e,d,f,g,h)}}return NaN},"yyyy-Www"),month:kb("month",Ud,Lb(Ud,["yyyy","MM"]),"yyyy-MM"),number:function(a,b,d,c,e,f){Ld(a,b,d,c);jb(a,b,d,c,e,f);c.$$parserName= +"number";c.$parsers.push(function(a){if(c.$isEmpty(a))return null;if(Jg.test(a))return parseFloat(a)});c.$formatters.push(function(a){if(!c.$isEmpty(a)){if(!Q(a))throw lb("numfmt",a);a=a.toString()}return a});if(x(d.min)||d.ngMin){var g;c.$validators.min=function(a){return c.$isEmpty(a)||y(g)||a>=g};d.$observe("min",function(a){x(a)&&!Q(a)&&(a=parseFloat(a,10));g=Q(a)&&!isNaN(a)?a:void 0;c.$validate()})}if(x(d.max)||d.ngMax){var h;c.$validators.max=function(a){return c.$isEmpty(a)||y(h)||a<=h};d.$observe("max", +function(a){x(a)&&!Q(a)&&(a=parseFloat(a,10));h=Q(a)&&!isNaN(a)?a:void 0;c.$validate()})}},url:function(a,b,d,c,e,f){jb(a,b,d,c,e,f);lc(c);c.$$parserName="url";c.$validators.url=function(a,b){var d=a||b;return c.$isEmpty(d)||Hg.test(d)}},email:function(a,b,d,c,e,f){jb(a,b,d,c,e,f);lc(c);c.$$parserName="email";c.$validators.email=function(a,b){var d=a||b;return c.$isEmpty(d)||Ig.test(d)}},radio:function(a,b,d,c){y(d.name)&&b.attr("name",++nb);b.on("click",function(a){b[0].checked&&c.$setViewValue(d.value, +a&&a.type)});c.$render=function(){b[0].checked=d.value==c.$viewValue};d.$observe("value",c.$render)},checkbox:function(a,b,d,c,e,f,g,h){var k=Md(h,a,"ngTrueValue",d.ngTrueValue,!0),l=Md(h,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 pa(a,k)});c.$parsers.push(function(a){return a?k:l})},hidden:C,button:C,submit:C,reset:C, +file:C},Dc=["$browser","$sniffer","$filter","$parse",function(a,b,d,c){return{restrict:"E",require:["?ngModel"],link:{pre:function(e,f,g,h){h[0]&&(Wd[P(g.type)]||Wd.text)(e,f,g,h[0],b,a,d,c)}}}}],Kg=/^(true|false|\d+)$/,Te=function(){return{restrict:"A",priority:100,compile:function(a,b){return Kg.test(b.ngValue)?function(a,b,e){e.$set("value",a.$eval(e.ngValue))}:function(a,b,e){a.$watch(e.ngValue,function(a){e.$set("value",a)})}}}},te=["$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=y(a)?"":a})}}}}],ve=["$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=y(a)?"":a})}}}}],ue=["$sce","$parse","$compile",function(a,b,d){return{restrict:"A",compile:function(c,e){var f=b(e.ngBindHtml),g= +b(e.ngBindHtml,function(a){return(a||"").toString()});d.$$addBindingClass(c);return function(b,c,e){d.$$addBindingInfo(c,e.ngBindHtml);b.$watch(g,function(){c.html(a.getTrustedHtml(f(b))||"")})}}}}],Se=da({restrict:"A",require:"ngModel",link:function(a,b,d,c){c.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),we=mc("",!0),ye=mc("Odd",0),xe=mc("Even",1),ze=La({compile:function(a,b){b.$set("ngCloak",void 0);a.removeClass("ng-cloak")}}),Ae=[function(){return{restrict:"A",scope:!0,controller:"@", +priority:500}}],Ic={},Lg={blur:!0,focus:!0};q("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "),function(a){var b=xa("ng-"+a);Ic[b]=["$parse","$rootScope",function(d,c){return{restrict:"A",compile:function(e,f){var g=d(f[b],null,!0);return function(b,d){d.on(a,function(d){var e=function(){g(b,{$event:d})};Lg[a]&&c.$$phase?b.$evalAsync(e):b.$apply(e)})}}}}]});var De=["$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 h,k,l;d.$watch(e.ngIf,function(d){d?k||g(function(d,f){k=f;d[d.length++]=b.$$createComment("end ngIf",e.ngIf);h={clone:d};a.enter(d,c.parent(),c)}):(l&&(l.remove(),l=null),k&&(k.$destroy(),k=null),h&&(l=rb(h.clone),a.leave(l).then(function(){l=null}),h=null))})}}}],Ee=["$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||"",h=e.autoscroll;return function(c,e,n,m,r){var q=0,s,w,p,y=function(){w&&(w.remove(),w=null);s&&(s.$destroy(),s=null);p&&(d.leave(p).then(function(){w=null}),w=p,p=null)};c.$watch(f,function(f){var n=function(){!x(h)||h&&!c.$eval(h)||b()},u=++q;f?(a(f,!0).then(function(a){if(!c.$$destroyed&&u===q){var b=c.$new();m.template=a;a=r(b,function(a){y();d.enter(a,null,e).then(n)});s=b;p=a;s.$emit("$includeContentLoaded", +f);c.$eval(g)}},function(){c.$$destroyed||u!==q||(y(),c.$emit("$includeContentError",f))}),c.$emit("$includeContentRequested",f)):(y(),m.template=null)})}}}}],Ve=["$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(Lc(e.template,v.document).childNodes)(b,function(a){d.append(a)},{futureParentElement:d})):(d.html(e.template),a(d.contents())(b))}}}],Fe=La({priority:450,compile:function(){return{pre:function(a, +b,d){a.$eval(d.ngInit)}}}}),Re=function(){return{restrict:"A",priority:100,require:"ngModel",link:function(a,b,d,c){var e=b.attr(d.$attr.ngList)||", ",f="false"!==d.ngTrim,g=f?V(e):e;c.$parsers.push(function(a){if(!y(a)){var b=[];a&&q(a.split(g),function(a){a&&b.push(f?V(a):a)});return b}});c.$formatters.push(function(a){if(K(a))return a.join(e)});c.$isEmpty=function(a){return!a||!a.length}}}},mb="ng-valid",Nd="ng-invalid",Ua="ng-pristine",Kb="ng-dirty",Pd="ng-pending",lb=O("ngModel"),Mg=["$scope", +"$exceptionHandler","$attrs","$element","$parse","$animate","$timeout","$rootScope","$q","$interpolate",function(a,b,d,c,e,f,g,h,k,l){this.$modelValue=this.$viewValue=Number.NaN;this.$$rawModelValue=void 0;this.$validators={};this.$asyncValidators={};this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$untouched=!0;this.$touched=!1;this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=!1;this.$error={};this.$$success={};this.$pending=void 0;this.$name=l(d.name||"",!1)(a); +this.$$parentForm=Jb;var n=e(d.ngModel),m=n.assign,r=n,s=m,v=null,w,p=this;this.$$setOptions=function(a){if((p.$options=a)&&a.getterSetter){var b=e(d.ngModel+"()"),f=e(d.ngModel+"($$$p)");r=function(a){var c=n(a);E(c)&&(c=b(a));return c};s=function(a,b){E(n(a))?f(a,{$$$p:b}):m(a,b)}}else if(!n.assign)throw lb("nonassign",d.ngModel,wa(c));};this.$render=C;this.$isEmpty=function(a){return y(a)||""===a||null===a||a!==a};this.$$updateEmptyClasses=function(a){p.$isEmpty(a)?(f.removeClass(c,"ng-not-empty"), +f.addClass(c,"ng-empty")):(f.removeClass(c,"ng-empty"),f.addClass(c,"ng-not-empty"))};var H=0;Jd({ctrl:this,$element:c,set:function(a,b){a[b]=!0},unset:function(a,b){delete a[b]},$animate:f});this.$setPristine=function(){p.$dirty=!1;p.$pristine=!0;f.removeClass(c,Kb);f.addClass(c,Ua)};this.$setDirty=function(){p.$dirty=!0;p.$pristine=!1;f.removeClass(c,Ua);f.addClass(c,Kb);p.$$parentForm.$setDirty()};this.$setUntouched=function(){p.$touched=!1;p.$untouched=!0;f.setClass(c,"ng-untouched","ng-touched")}; +this.$setTouched=function(){p.$touched=!0;p.$untouched=!1;f.setClass(c,"ng-touched","ng-untouched")};this.$rollbackViewValue=function(){g.cancel(v);p.$viewValue=p.$$lastCommittedViewValue;p.$render()};this.$validate=function(){if(!Q(p.$modelValue)||!isNaN(p.$modelValue)){var a=p.$$rawModelValue,b=p.$valid,c=p.$modelValue,d=p.$options&&p.$options.allowInvalid;p.$$runValidators(a,p.$$lastCommittedViewValue,function(e){d||b===e||(p.$modelValue=e?a:void 0,p.$modelValue!==c&&p.$$writeModelToScope())})}}; +this.$$runValidators=function(a,b,c){function d(){var c=!0;q(p.$validators,function(d,e){var g=d(a,b);c=c&&g;f(e,g)});return c?!0:(q(p.$asyncValidators,function(a,b){f(b,null)}),!1)}function e(){var c=[],d=!0;q(p.$asyncValidators,function(e,g){var h=e(a,b);if(!h||!E(h.then))throw lb("nopromise",h);f(g,void 0);c.push(h.then(function(){f(g,!0)},function(){d=!1;f(g,!1)}))});c.length?k.all(c).then(function(){g(d)},C):g(!0)}function f(a,b){h===H&&p.$setValidity(a,b)}function g(a){h===H&&c(a)}H++;var h= +H;(function(){var a=p.$$parserName||"parse";if(y(w))f(a,null);else return w||(q(p.$validators,function(a,b){f(b,null)}),q(p.$asyncValidators,function(a,b){f(b,null)})),f(a,w),w;return!0})()?d()?e():g(!1):g(!1)};this.$commitViewValue=function(){var a=p.$viewValue;g.cancel(v);if(p.$$lastCommittedViewValue!==a||""===a&&p.$$hasNativeValidators)p.$$updateEmptyClasses(a),p.$$lastCommittedViewValue=a,p.$pristine&&this.$setDirty(),this.$$parseAndValidate()};this.$$parseAndValidate=function(){var b=p.$$lastCommittedViewValue; +if(w=y(b)?void 0:!0)for(var c=0;ce||c.$isEmpty(b)||b.length<=e}}}}},Gc=function(){return{restrict:"A",require:"?ngModel",link:function(a,b,d,c){if(c){var e=0;d.$observe("minlength",function(a){e=X(a)||0;c.$validate()});c.$validators.minlength=function(a,b){return c.$isEmpty(b)||b.length>=e}}}}};v.angular.bootstrap?v.console&&console.log("WARNING: Tried to load angular more than once."):(ie(),ke(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"}})}]),B(v.document).ready(function(){ee(v.document,yc)}))})(window);!window.angular.$$csp().noInlineStyle&&window.angular.element(document.head).prepend(''); +//# sourceMappingURL=angular.min.js.map diff --git a/js/vendor/jquery-1.12.2.js b/js/vendor/jquery-1.12.2.js new file mode 100644 index 0000000..61f168b --- /dev/null +++ b/js/vendor/jquery-1.12.2.js @@ -0,0 +1,11022 @@ +/*! + * jQuery JavaScript Library v1.12.2 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-03-17T17:44Z + */ + +(function( global, factory ) { + + if ( typeof module === "object" && typeof module.exports === "object" ) { + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Support: Firefox 18+ +// Can't be in strict mode, several libs including ASP.NET trace +// the stack via arguments.caller.callee and Firefox dies if +// you try to trace through "use strict" call chains. (#13335) +//"use strict"; +var deletedIds = []; + +var document = window.document; + +var slice = deletedIds.slice; + +var concat = deletedIds.concat; + +var push = deletedIds.push; + +var indexOf = deletedIds.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var support = {}; + + + +var + version = "1.12.2", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android<4.1, IE<9 + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // Start with an empty selector + selector: "", + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num != null ? + + // Return just the one element from the set + ( num < 0 ? this[ num + this.length ] : this[ num ] ) : + + // Return all the elements in a clean array + slice.call( this ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + ret.context = this.context; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: deletedIds.sort, + splice: deletedIds.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var src, copyIsArray, copy, name, options, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = jQuery.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type( obj ) === "array"; + }, + + isWindow: function( obj ) { + /* jshint eqeqeq: false */ + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + + // parseFloat NaNs numeric-cast false positives (null|true|false|"") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + // adding 1 corrects loss of precision from parseFloat (#15100) + var realStringObj = obj && obj.toString(); + return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0; + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + isPlainObject: function( obj ) { + var key; + + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call( obj, "constructor" ) && + !hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) { + return false; + } + } catch ( e ) { + + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Support: IE<9 + // Handle iteration over inherited properties before own properties. + if ( !support.ownFirst ) { + for ( key in obj ) { + return hasOwn.call( obj, key ); + } + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && jQuery.trim( data ) ) { + + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); // jscs:ignore requireDotNotation + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android<4.1, IE<9 + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + var len; + + if ( arr ) { + if ( indexOf ) { + return indexOf.call( arr, elem, i ); + } + + len = arr.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + + // Skip accessing in sparse arrays + if ( i in arr && arr[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + while ( j < len ) { + first[ i++ ] = second[ j++ ]; + } + + // Support: IE<9 + // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists) + if ( len !== len ) { + while ( second[ j ] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var args, proxy, tmp; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: function() { + return +( new Date() ); + }, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +// JSHint would error on this code due to the Symbol not being defined in ES5. +// Defining this global in .jshintrc would create a danger of using the global +// unguarded in another place, it seems safer to just disable JSHint for these +// three lines. +/* jshint ignore: start */ +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = deletedIds[ Symbol.iterator ]; +} +/* jshint ignore: end */ + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: iOS 8.2 (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.2.1 + * http://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2015-10-17 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // General-purpose constants + MAX_NEGATIVE = 1 << 31, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // http://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + rescape = /'|\\/g, + + // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }; + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, nidselect, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + nidselect = ridentifier.test( nid ) ? "#" + nid : "[id='" + nid + "']"; + while ( i-- ) { + groups[i] = nidselect + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created div and expects a boolean result + */ +function assert( fn ) { + var div = document.createElement("div"); + + try { + return !!fn( div ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( div.parentNode ) { + div.parentNode.removeChild( div ); + } + // release memory in IE + div = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + ( ~b.sourceIndex || MAX_NEGATIVE ) - + ( ~a.sourceIndex || MAX_NEGATIVE ); + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, parent, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( (parent = document.defaultView) && parent.top !== parent ) { + // Support: IE 11 + if ( parent.addEventListener ) { + parent.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( parent.attachEvent ) { + parent.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( div ) { + div.className = "i"; + return !div.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( div ) { + div.appendChild( document.createComment("") ); + return !div.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( div ) { + docElem.appendChild( div ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID find and filter + if ( support.getById ) { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var m = context.getElementById( id ); + return m ? [ m ] : []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + } else { + // Support: IE6/7 + // getElementById is not reliable as a find shortcut + delete Expr.find["ID"]; + + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See http://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + docElem.appendChild( div ).innerHTML = "
" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( div.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibing-combinator selector` fails + if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( div ) { + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + div.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( div.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + div.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( div, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( (oldCache = uniqueCache[ dir ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ dir ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + support.getById && context.nodeType === 9 && documentIsHTML && + Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( div1 ) { + // Should return 1, but returns 4 (following) + return div1.compareDocumentPosition( document.createElement("div") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( div ) { + div.innerHTML = ""; + return div.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( div ) { + div.innerHTML = ""; + div.firstChild.setAttribute( "value", "" ); + return div.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( div ) { + return div.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + +var rsingleTag = ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ ); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + /* jshint -W018 */ + return !!qualifier.call( elem, i, elem ) !== not; + } ); + + } + + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + + } + + if ( typeof qualifier === "string" ) { + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + qualifier = jQuery.filter( qualifier, elements ); + } + + return jQuery.grep( elements, function( elem ) { + return ( jQuery.inArray( elem, qualifier ) > -1 ) !== not; + } ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 && elem.nodeType === 1 ? + jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : + jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, + ret = [], + self = this, + len = self.length; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + // Needed because $( selector, context ) becomes $( context ).find( selector ) + ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); + ret.selector = this.selector ? this.selector + " " + selector : selector; + return ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // init accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector.charAt( 0 ) === "<" && + selector.charAt( selector.length - 1 ) === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[ 2 ] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[ 0 ] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this.context = this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return typeof root.ready !== "undefined" ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var i, + targets = jQuery( target, this ), + len = targets.length; + + return this.filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( pos ? + pos.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[ 0 ], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem, this ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + do { + cur = cur[ dir ]; + } while ( cur && cur.nodeType !== 1 ); + + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + ret = jQuery.uniqueSort( ret ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + } + + return this.pushStack( ret ); + }; +} ); +var rnotwhite = ( /\S+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( jQuery.isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = true; + if ( !memory ) { + self.disable(); + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks( "once memory" ), "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), "rejected" ], + [ "notify", "progress", jQuery.Callbacks( "memory" ) ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this === promise ? newDefer.promise() : this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( function() { + + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? promise : this, arguments ); + return this; + }; + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || + ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. + // If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( values === progressValues ) { + deferred.notifyWith( contexts, values ); + + } else if ( !( --remaining ) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .progress( updateFunc( i, progressContexts, progressValues ) ) + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ); + } else { + --remaining; + } + } + } + + // if we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +} ); + + +// The deferred used on DOM ready +var readyList; + +jQuery.fn.ready = function( fn ) { + + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.triggerHandler ) { + jQuery( document ).triggerHandler( "ready" ); + jQuery( document ).off( "ready" ); + } + } +} ); + +/** + * Clean-up method for dom ready events + */ +function detach() { + if ( document.addEventListener ) { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + + } else { + document.detachEvent( "onreadystatechange", completed ); + window.detachEvent( "onload", completed ); + } +} + +/** + * The ready event handler and self cleanup method + */ +function completed() { + + // readyState === "complete" is good enough for us to call the dom ready in oldIE + if ( document.addEventListener || + window.event.type === "load" || + document.readyState === "complete" ) { + + detach(); + jQuery.ready(); + } +} + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called + // after the browser event has already occurred. + // Support: IE6-10 + // Older IE sometimes signals "interactive" too soon + if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + + // Standards-based browsers support DOMContentLoaded + } else if ( document.addEventListener ) { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); + + // If IE event model is used + } else { + + // Ensure firing before onload, maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", completed ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", completed ); + + // If IE and not a frame + // continually check to see if the document is ready + var top = false; + + try { + top = window.frameElement == null && document.documentElement; + } catch ( e ) {} + + if ( top && top.doScroll ) { + ( function doScrollCheck() { + if ( !jQuery.isReady ) { + + try { + + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + top.doScroll( "left" ); + } catch ( e ) { + return window.setTimeout( doScrollCheck, 50 ); + } + + // detach all dom ready events + detach(); + + // and execute any waiting functions + jQuery.ready(); + } + } )(); + } + } + } + return readyList.promise( obj ); +}; + +// Kick off the DOM ready check even if the user does not +jQuery.ready.promise(); + + + + +// Support: IE<9 +// Iteration over object's inherited properties before its own +var i; +for ( i in jQuery( support ) ) { + break; +} +support.ownFirst = i === "0"; + +// Note: most support tests are defined in their respective modules. +// false until the test is run +support.inlineBlockNeedsLayout = false; + +// Execute ASAP in case we need to set body.style.zoom +jQuery( function() { + + // Minified: var a,b,c,d + var val, div, body, container; + + body = document.getElementsByTagName( "body" )[ 0 ]; + if ( !body || !body.style ) { + + // Return for frameset docs that don't have a body + return; + } + + // Setup + div = document.createElement( "div" ); + container = document.createElement( "div" ); + container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; + body.appendChild( container ).appendChild( div ); + + if ( typeof div.style.zoom !== "undefined" ) { + + // Support: IE<8 + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1"; + + support.inlineBlockNeedsLayout = val = div.offsetWidth === 3; + if ( val ) { + + // Prevent IE 6 from affecting layout for positioned elements #11048 + // Prevent IE from shrinking the body in IE 7 mode #12869 + // Support: IE<8 + body.style.zoom = 1; + } + } + + body.removeChild( container ); +} ); + + +( function() { + var div = document.createElement( "div" ); + + // Support: IE<9 + support.deleteExpando = true; + try { + delete div.test; + } catch ( e ) { + support.deleteExpando = false; + } + + // Null elements to avoid leaks in IE. + div = null; +} )(); +var acceptData = function( elem ) { + var noData = jQuery.noData[ ( elem.nodeName + " " ).toLowerCase() ], + nodeType = +elem.nodeType || 1; + + // Do not set data on non-element DOM nodes because it will not be cleared (#8335). + return nodeType !== 1 && nodeType !== 9 ? + false : + + // Nodes accept data unless otherwise specified; rejection can be conditional + !noData || noData !== true && elem.getAttribute( "classid" ) === noData; +}; + + + + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /([A-Z])/g; + +function dataAttr( elem, key, data ) { + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + var name; + for ( name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[ name ] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + +function internalData( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !acceptData( elem ) ) { + return; + } + + var ret, thisCache, + internalKey = jQuery.expando, + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( ( !id || !cache[ id ] || ( !pvt && !cache[ id ].data ) ) && + data === undefined && typeof name === "string" ) { + return; + } + + if ( !id ) { + + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + + // Avoid exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + cache[ id ] = isNode ? {} : { toJSON: jQuery.noop }; + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( typeof name === "string" ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; +} + +function internalRemoveData( elem, name, pvt ) { + if ( !acceptData( elem ) ) { + return; + } + + var thisCache, i, + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split( " " ); + } + } + } else { + + // If "name" is an array of keys... + // When data is initially created, via ("key", "val") signature, + // keys will be converted to camelCase. + // Since there is no way to tell _how_ a key was added, remove + // both plain key and camelCase key. #12786 + // This will only penalize the array argument path. + name = name.concat( jQuery.map( name, jQuery.camelCase ) ); + } + + i = name.length; + while ( i-- ) { + delete thisCache[ name[ i ] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( pvt ? !isEmptyDataObject( thisCache ) : !jQuery.isEmptyObject( thisCache ) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject( cache[ id ] ) ) { + return; + } + } + + // Destroy the cache + if ( isNode ) { + jQuery.cleanData( [ elem ], true ); + + // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) + /* jshint eqeqeq: false */ + } else if ( support.deleteExpando || cache != cache.window ) { + /* jshint eqeqeq: true */ + delete cache[ id ]; + + // When all else fails, undefined + } else { + cache[ id ] = undefined; + } +} + +jQuery.extend( { + cache: {}, + + // The following elements (space-suffixed to avoid Object.prototype collisions) + // throw uncatchable exceptions if you attempt to set expando properties + noData: { + "applet ": true, + "embed ": true, + + // ...but Flash objects (which have this classid) *can* handle expandos + "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[ jQuery.expando ] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data ) { + return internalData( elem, name, data ); + }, + + removeData: function( elem, name ) { + return internalRemoveData( elem, name ); + }, + + // For internal use only. + _data: function( elem, name, data ) { + return internalData( elem, name, data, true ); + }, + + _removeData: function( elem, name ) { + return internalRemoveData( elem, name, true ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Special expections of .data basically thwart jQuery.access, + // so implement the relevant behavior ourselves + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE11+ + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + jQuery.data( this, key ); + } ); + } + + return arguments.length > 1 ? + + // Sets one value + this.each( function() { + jQuery.data( this, key, value ); + } ) : + + // Gets one value + // Try to fetch any internally stored data first + elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined; + }, + + removeData: function( key ) { + return this.each( function() { + jQuery.removeData( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray( data ) ) { + queue = jQuery._data( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // not intended for public consumption - generates a queueHooks object, + // or returns the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return jQuery._data( elem, key ) || jQuery._data( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + jQuery._removeData( elem, type + "queue" ); + jQuery._removeData( elem, key ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = jQuery._data( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); + + +( function() { + var shrinkWrapBlocksVal; + + support.shrinkWrapBlocks = function() { + if ( shrinkWrapBlocksVal != null ) { + return shrinkWrapBlocksVal; + } + + // Will be changed later if needed. + shrinkWrapBlocksVal = false; + + // Minified: var b,c,d + var div, body, container; + + body = document.getElementsByTagName( "body" )[ 0 ]; + if ( !body || !body.style ) { + + // Test fired too early or in an unsupported environment, exit. + return; + } + + // Setup + div = document.createElement( "div" ); + container = document.createElement( "div" ); + container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; + body.appendChild( container ).appendChild( div ); + + // Support: IE6 + // Check if elements with layout shrink-wrap their children + if ( typeof div.style.zoom !== "undefined" ) { + + // Reset CSS: box-sizing; display; margin; border + div.style.cssText = + + // Support: Firefox<29, Android 2.3 + // Vendor-prefix box-sizing + "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" + + "box-sizing:content-box;display:block;margin:0;border:0;" + + "padding:1px;width:1px;zoom:1"; + div.appendChild( document.createElement( "div" ) ).style.width = "5px"; + shrinkWrapBlocksVal = div.offsetWidth !== 3; + } + + body.removeChild( container ); + + return shrinkWrapBlocksVal; + }; + +} )(); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHidden = function( elem, el ) { + + // isHidden might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || + !jQuery.contains( elem.ownerDocument, elem ); + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, + scale = 1, + maxIterations = 20, + currentValue = tween ? + function() { return tween.cur(); } : + function() { return jQuery.css( elem, prop, "" ); }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + do { + + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + initialInUnit = initialInUnit / scale; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // Break the loop if scale is unchanged or perfect, or if we've just had enough. + } while ( + scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations + ); + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + length = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < length; i++ ) { + fn( + elems[ i ], + key, + raw ? value : value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[ 0 ], key ) : emptyGet; +}; +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([\w:-]+)/ ); + +var rscriptType = ( /^$|\/(?:java|ecma)script/i ); + +var rleadingWhitespace = ( /^\s+/ ); + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|" + + "details|dialog|figcaption|figure|footer|header|hgroup|main|" + + "mark|meter|nav|output|picture|progress|section|summary|template|time|video"; + + + +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + + +( function() { + var div = document.createElement( "div" ), + fragment = document.createDocumentFragment(), + input = document.createElement( "input" ); + + // Setup + div.innerHTML = "
a"; + + // IE strips leading whitespace when .innerHTML is used + support.leadingWhitespace = div.firstChild.nodeType === 3; + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + support.tbody = !div.getElementsByTagName( "tbody" ).length; + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + support.htmlSerialize = !!div.getElementsByTagName( "link" ).length; + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + support.html5Clone = + document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav>"; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + input.type = "checkbox"; + input.checked = true; + fragment.appendChild( input ); + support.appendChecked = input.checked; + + // Make sure textarea (and checkbox) defaultValue is properly cloned + // Support: IE6-IE11+ + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // #11217 - WebKit loses check when the name is after the checked attribute + fragment.appendChild( div ); + + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input = document.createElement( "input" ); + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 + // old WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE<9 + // Cloned elements keep attachEvent handlers, we use addEventListener on IE9+ + support.noCloneEvent = !!div.addEventListener; + + // Support: IE<9 + // Since attributes and properties are the same in IE, + // cleanData must set properties to undefined rather than use removeAttribute + div[ jQuery.expando ] = 1; + support.attributes = !div.getAttribute( jQuery.expando ); +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
", "
" ], + area: [ 1, "", "" ], + + // Support: IE8 + param: [ 1, "", "" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + col: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, + // unless wrapped in a div with non-breaking characters in front of it. + _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
", "
" ] +}; + +// Support: IE8-IE9 +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + var elems, elem, + i = 0, + found = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( tag || "*" ) : + typeof context.querySelectorAll !== "undefined" ? + context.querySelectorAll( tag || "*" ) : + undefined; + + if ( !found ) { + for ( found = [], elems = context.childNodes || context; + ( elem = elems[ i ] ) != null; + i++ + ) { + if ( !tag || jQuery.nodeName( elem, tag ) ) { + found.push( elem ); + } else { + jQuery.merge( found, getAll( elem, tag ) ); + } + } + } + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], found ) : + found; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var elem, + i = 0; + for ( ; ( elem = elems[ i ] ) != null; i++ ) { + jQuery._data( + elem, + "globalEval", + !refElements || jQuery._data( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/, + rtbody = / from table fragments + if ( !support.tbody ) { + + // String was a , *may* have spurious + elem = tag === "table" && !rtbody.test( elem ) ? + tmp.firstChild : + + // String was a bare or + wrap[ 1 ] === "
" && !rtbody.test( elem ) ? + tmp : + 0; + + j = elem && elem.childNodes.length; + while ( j-- ) { + if ( jQuery.nodeName( ( tbody = elem.childNodes[ j ] ), "tbody" ) && + !tbody.childNodes.length ) { + + elem.removeChild( tbody ); + } + } + } + + jQuery.merge( nodes, tmp.childNodes ); + + // Fix #12392 for WebKit and IE > 9 + tmp.textContent = ""; + + // Fix #12392 for oldIE + while ( tmp.firstChild ) { + tmp.removeChild( tmp.firstChild ); + } + + // Remember the top-level container for proper cleanup + tmp = safe.lastChild; + } + } + } + + // Fix #11356: Clear elements from fragment + if ( tmp ) { + safe.removeChild( tmp ); + } + + // Reset defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + if ( !support.appendChecked ) { + jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); + } + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( safe.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + tmp = null; + + return safe; +} + + +( function() { + var i, eventName, + div = document.createElement( "div" ); + + // Support: IE<9 (lack submit/change bubble), Firefox (lack focus(in | out) events) + for ( i in { submit: true, change: true, focusin: true } ) { + eventName = "on" + i; + + if ( !( support[ i ] = eventName in window ) ) { + + // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) + div.setAttribute( eventName, "t" ); + support[ i ] = div.attributes[ eventName ].expando === false; + } + } + + // Null elements to avoid leaks in IE. + div = null; +} )(); + + +var rformElems = /^(?:input|select|textarea)$/i, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE9 +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + var tmp, events, t, handleObjIn, + special, eventHandle, handleObj, + handlers, type, namespaces, origType, + elemData = jQuery._data( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && + ( !e || jQuery.event.triggered !== e.type ) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + + // Add elem as a property of the handle fn to prevent a memory leak + // with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + var j, handleObj, tmp, + origCount, t, events, + special, handlers, type, + namespaces, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery._removeData( elem, "events" ); + } + }, + + trigger: function( event, data, elem, onlyHandlers ) { + var handle, ontype, cur, + bubbleType, special, tmp, i, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && + jQuery._data( cur, "handle" ); + + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( + ( !special._default || + special._default.apply( eventPath.pop(), data ) === false + ) && acceptData( elem ) + ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + try { + elem[ type ](); + } catch ( e ) { + + // IE<9 dies on focus/blur to hidden element (#1486,#12518) + // only reproducible on winXP IE8 native, not IE9 in IE8 mode + } + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event ); + + var i, j, ret, matched, handleObj, + handlerQueue = [], + args = slice.call( arguments ), + handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, matches, sel, handleObj, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Support (at least): Chrome, IE9 + // Find delegate handlers + // Black-hole SVG instance trees (#13180) + // + // Support: Firefox<=42+ + // Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343) + if ( delegateCount && cur.nodeType && + ( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) { + + /* jshint eqeqeq: false */ + for ( ; cur != this; cur = cur.parentNode || this ) { + /* jshint eqeqeq: true */ + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push( { elem: cur, handlers: matches } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, copy, + type = event.type, + originalEvent = event, + fixHook = this.fixHooks[ type ]; + + if ( !fixHook ) { + this.fixHooks[ type ] = fixHook = + rmouseEvent.test( type ) ? this.mouseHooks : + rkeyEvent.test( type ) ? this.keyHooks : + {}; + } + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = new jQuery.Event( originalEvent ); + + i = copy.length; + while ( i-- ) { + prop = copy[ i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Support: IE<9 + // Fix target property (#1925) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Support: Safari 6-8+ + // Target should not be a text node (#504, #13143) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Support: IE<9 + // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) + event.metaKey = !!event.metaKey; + + return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + props: ( "altKey bubbles cancelable ctrlKey currentTarget detail eventPhase " + + "metaKey relatedTarget shiftKey target timeStamp view which" ).split( " " ), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split( " " ), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: ( "button buttons clientX clientY fromElement offsetX offsetY " + + "pageX pageY screenX screenY toElement" ).split( " " ), + filter: function( event, original ) { + var body, eventDoc, doc, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - + ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - + ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? + original.toElement : + fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + try { + this.focus(); + return false; + } catch ( e ) { + + // Support: IE<9 + // If we error on focus to hidden element (#1486, #12518), + // let .trigger() run the handlers + } + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return jQuery.nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + }, + + // Piggyback on a donor event to simulate a different one + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + + // Previously, `originalEvent: {}` was set here, so stopPropagation call + // would not be triggered on donor event, since in our own + // jQuery.event.stopPropagation function we had a check for existence of + // originalEvent.stopPropagation method, so, consequently it would be a noop. + // + // Guard for simulated events was moved to jQuery.event.stopPropagation function + // since `originalEvent` should point to the original event for the + // constancy with other events and for more focused logic + } + ); + + jQuery.event.trigger( e, null, elem ); + + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } + } : + function( elem, type, handle ) { + var name = "on" + type; + + if ( elem.detachEvent ) { + + // #8545, #7054, preventing memory leaks for custom events in IE6-8 + // detachEvent needed property on element, by name of that event, + // to properly expose it to GC + if ( typeof elem[ name ] === "undefined" ) { + elem[ name ] = null; + } + + elem.detachEvent( name, handle ); + } + }; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: IE < 9, Android < 4.0 + src.returnValue === false ? + returnTrue : + returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + if ( !e ) { + return; + } + + // If preventDefault exists, run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // Support: IE + // Otherwise set the returnValue property of the original event to false + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( !e || this.isSimulated ) { + return; + } + + // If stopPropagation exists, run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + + // Support: IE + // Set the cancelBubble property of the original event to true + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && e.stopImmediatePropagation ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://code.google.com/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +// IE submit delegation +if ( !support.submit ) { + + jQuery.event.special.submit = { + setup: function() { + + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? + + // Support: IE <=8 + // We use jQuery.prop instead of elem.form + // to allow fixing the IE8 delegated submit issue (gh-2332) + // by 3rd party polyfills/workarounds. + jQuery.prop( elem, "form" ) : + undefined; + + if ( form && !jQuery._data( form, "submit" ) ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submitBubble = true; + } ); + jQuery._data( form, "submit", true ); + } + } ); + + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + + // If form was submitted by the user, bubble the event up the tree + if ( event._submitBubble ) { + delete event._submitBubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event ); + } + } + }, + + teardown: function() { + + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !support.change ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._justChanged = true; + } + } ); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._justChanged && !event.isTrigger ) { + this._justChanged = false; + } + + // Allow triggered, simulated change events (#11500) + jQuery.event.simulate( "change", this, event ); + } ); + } + return false; + } + + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "change" ) ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event ); + } + } ); + jQuery._data( elem, "change", true ); + } + } ); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || + ( elem.type !== "radio" && elem.type !== "checkbox" ) ) { + + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return !rformElems.test( this.nodeName ); + } + }; +} + +// Support: Firefox +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome, Safari +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://code.google.com/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = jQuery._data( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + jQuery._data( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = jQuery._data( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + jQuery._removeData( doc, fix ); + } else { + jQuery._data( doc, fix, attaches ); + } + } + }; + } ); +} + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + }, + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +var rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, + rnoshimcache = new RegExp( "<(?:" + nodeNames + ")[\\s/>]", "i" ), + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi, + + // Support: IE 10-11, Edge 10240+ + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g, + safeFragment = createSafeFragment( document ), + fragmentDiv = safeFragment.appendChild( document.createElement( "div" ) ); + +// Support: IE<8 +// Manipulating tables requires a tbody +function manipulationTarget( elem, content ) { + return jQuery.nodeName( elem, "table" ) && + jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? + + elem.getElementsByTagName( "tbody" )[ 0 ] || + elem.appendChild( elem.ownerDocument.createElement( "tbody" ) ) : + elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( jQuery.find.attr( elem, "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + return elem; +} + +function cloneCopyEvent( src, dest ) { + if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { + return; + } + + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; + + if ( events ) { + delete curData.handle; + curData.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } +} + +function fixCloneNodeIssues( src, dest ) { + var nodeName, e, data; + + // We do not need to do anything for non-Elements + if ( dest.nodeType !== 1 ) { + return; + } + + nodeName = dest.nodeName.toLowerCase(); + + // IE6-8 copies events bound via attachEvent when using cloneNode. + if ( !support.noCloneEvent && dest[ jQuery.expando ] ) { + data = jQuery._data( dest ); + + for ( e in data.events ) { + jQuery.removeEvent( dest, e, data.handle ); + } + + // Event data gets referenced instead of copied if the expando gets copied too + dest.removeAttribute( jQuery.expando ); + } + + // IE blanks contents when cloning scripts, and tries to evaluate newly-set text + if ( nodeName === "script" && dest.text !== src.text ) { + disableScript( dest ).text = src.text; + restoreScript( dest ); + + // IE6-10 improperly clones children of object elements using classid. + // IE10 throws NoModificationAllowedError if parent is null, #12132. + } else if ( nodeName === "object" ) { + if ( dest.parentNode ) { + dest.outerHTML = src.outerHTML; + } + + // This path appears unavoidable for IE9. When cloning an object + // element in IE9, the outerHTML strategy above is not sufficient. + // If the src has innerHTML and the destination does not, + // copy the src.innerHTML into the dest.innerHTML. #10324 + if ( support.html5Clone && ( src.innerHTML && !jQuery.trim( dest.innerHTML ) ) ) { + dest.innerHTML = src.innerHTML; + } + + } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + + // IE6-8 fails to persist the checked state of a cloned checkbox + // or radio button. Worse, IE6-7 fail to give the cloned element + // a checked appearance if the defaultChecked value isn't also set + + dest.defaultChecked = dest.checked = src.checked; + + // IE6-7 get confused and end up setting the value of a cloned + // checkbox/radio button to an empty string instead of "on" + if ( dest.value !== src.value ) { + dest.value = src.value; + } + + // IE6-8 fails to return the selected option to the default selected + // state when cloning options + } else if ( nodeName === "option" ) { + dest.defaultSelected = dest.selected = src.defaultSelected; + + // IE6-8 fails to set the defaultValue to the correct value when + // cloning other types of input fields + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var first, node, hasScripts, + scripts, doc, fragment, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android<4.1, PhantomJS<2 + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !jQuery._data( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + jQuery.globalEval( + ( node.text || node.textContent || node.innerHTML || "" ) + .replace( rcleanScript, "" ) + ); + } + } + } + } + + // Fix #11809: Avoid leaking memory + fragment = first = null; + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + elems = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = elems[ i ] ) != null; i++ ) { + + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var destElements, node, clone, i, srcElements, + inPage = jQuery.contains( elem.ownerDocument, elem ); + + if ( support.html5Clone || jQuery.isXMLDoc( elem ) || + !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { + + clone = elem.cloneNode( true ); + + // IE<=8 does not properly clone detached, unknown element nodes + } else { + fragmentDiv.innerHTML = elem.outerHTML; + fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); + } + + if ( ( !support.noCloneEvent || !support.noCloneChecked ) && + ( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + // Fix all IE cloning issues + for ( i = 0; ( node = srcElements[ i ] ) != null; ++i ) { + + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[ i ] ) { + fixCloneNodeIssues( node, destElements[ i ] ); + } + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0; ( node = srcElements[ i ] ) != null; i++ ) { + cloneCopyEvent( node, destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + destElements = srcElements = node = null; + + // Return the cloned set + return clone; + }, + + cleanData: function( elems, /* internal */ forceAcceptData ) { + var elem, type, id, data, + i = 0, + internalKey = jQuery.expando, + cache = jQuery.cache, + attributes = support.attributes, + special = jQuery.event.special; + + for ( ; ( elem = elems[ i ] ) != null; i++ ) { + if ( forceAcceptData || acceptData( elem ) ) { + + id = elem[ internalKey ]; + data = id && cache[ id ]; + + if ( data ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Remove cache only if it was not already removed by jQuery.event.remove + if ( cache[ id ] ) { + + delete cache[ id ]; + + // Support: IE<9 + // IE does not allow us to delete expando properties from nodes + // IE creates expando attributes along with the property + // IE does not have a removeAttribute function on Document nodes + if ( !attributes && typeof elem.removeAttribute !== "undefined" ) { + elem.removeAttribute( internalKey ); + + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://code.google.com/p/chromium/issues/detail?id=378607 + } else { + elem[ internalKey ] = undefined; + } + + deletedIds.push( id ); + } + } + } + } + } +} ); + +jQuery.fn.extend( { + + // Keep domManip exposed until 3.0 (gh-2225) + domManip: domManip, + + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().append( + ( this[ 0 ] && this[ 0 ].ownerDocument || document ).createTextNode( value ) + ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + } + + // Remove any remaining nodes + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + + // If this is a select, ensure that it displays empty (#12336) + // Support: IE<9 + if ( elem.options && jQuery.nodeName( elem, "select" ) ) { + elem.options.length = 0; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined ) { + return elem.nodeType === 1 ? + elem.innerHTML.replace( rinlinejQuery, "" ) : + undefined; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + ( support.htmlSerialize || !rnoshimcache.test( value ) ) && + ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + + // Remove element nodes and prevent memory leaks + elem = this[ i ] || {}; + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + i = 0, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); + + +var iframe, + elemdisplay = { + + // Support: Firefox + // We have to pre-define these values for FF (#10227) + HTML: "block", + BODY: "block" + }; + +/** + * Retrieve the actual display of a element + * @param {String} name nodeName of the element + * @param {Object} doc Document object + */ + +// Called only from within defaultDisplay +function actualDisplay( name, doc ) { + var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), + + display = jQuery.css( elem[ 0 ], "display" ); + + // We don't have any data stored on the element, + // so use "detach" method as fast way to get rid of the element + elem.detach(); + + return display; +} + +/** + * Try to determine the default display value of an element + * @param {String} nodeName + */ +function defaultDisplay( nodeName ) { + var doc = document, + display = elemdisplay[ nodeName ]; + + if ( !display ) { + display = actualDisplay( nodeName, doc ); + + // If the simple way fails, read from inside an iframe + if ( display === "none" || !display ) { + + // Use the already-created iframe if possible + iframe = ( iframe || jQuery( "