diff --git a/static/kevin-master/README.md b/static/kevin-master/README.md deleted file mode 100644 index d9f5cd0..0000000 --- a/static/kevin-master/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Killer Experimental Video Internet Noise, KEVIN - diff --git a/static/kevin-master/assets/bootstrap/css/bootstrap.min.css b/static/kevin-master/assets/bootstrap/css/bootstrap.min.css deleted file mode 100644 index b919506..0000000 --- a/static/kevin-master/assets/bootstrap/css/bootstrap.min.css +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Start Bootstrap - Landing Page 4.1.1 (https://startbootstrap.com/template-overviews/landing-page) - * Copyright 2013-2020, Start Bootstrap - * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap-landing-page/blob/master/LICENSE) - */ - -/*! - * Bootstrap v4.5.3 (https://getbootstrap.com/) - * Copyright 2011-2020 The Bootstrap Authors - * Copyright 2011-2020 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#868e96;--gray-dark:#343a40;--primary:#007bff;--secondary:#868e96;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,:after,:before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus:not(:focus-visible){outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;text-decoration-skip-ink:none}address{font-style:normal;line-height:inherit}address,dl,ol,ul{margin-bottom:1rem}dl,ol,ul{margin-top:0}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{border-style:none}img,svg{vertical-align:middle}svg{overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#868e96;text-align:left;caption-side:bottom}th{text-align:inherit;text-align:-webkit-match-parent}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem}.display-1,.display-2{font-weight:300;line-height:1.2}.display-2{font-size:5.5rem}.display-3{font-size:4.5rem}.display-3,.display-4{font-weight:300;line-height:1.2}.display-4{font-size:3.5rem}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-inline,.list-unstyled{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#868e96}.blockquote-footer:before{content:"\2014\00A0"}.img-fluid,.img-thumbnail{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#868e96}code{font-size:87.5%;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12,.col-auto,.col-lg,.col-lg-1,.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-lg-10,.col-lg-11,.col-lg-12,.col-lg-auto,.col-md,.col-md-1,.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-md-10,.col-md-11,.col-md-12,.col-md-auto,.col-sm,.col-sm-1,.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-sm-10,.col-sm-11,.col-sm-12,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-auto{position:relative;width:100%;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-3>*{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.row-cols-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-6>*{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-1{-ms-flex:0 0 8.33333%;flex:0 0 8.33333%;max-width:8.33333%}.col-2{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-5{-ms-flex:0 0 41.66667%;flex:0 0 41.66667%;max-width:41.66667%}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.33333%;flex:0 0 58.33333%;max-width:58.33333%}.col-8{-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-ms-flex:0 0 83.33333%;flex:0 0 83.33333%;max-width:83.33333%}.col-11{-ms-flex:0 0 91.66667%;flex:0 0 91.66667%;max-width:91.66667%}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-ms-flex-order:-1;order:-1}.order-last{-ms-flex-order:13;order:13}.order-0{-ms-flex-order:0;order:0}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-9{-ms-flex-order:9;order:9}.order-10{-ms-flex-order:10;order:10}.order-11{-ms-flex-order:11;order:11}.order-12{-ms-flex-order:12;order:12}.offset-1{margin-left:8.33333%}.offset-2{margin-left:16.66667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333%}.offset-5{margin-left:41.66667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333%}.offset-8{margin-left:66.66667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333%}.offset-11{margin-left:91.66667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-sm-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-sm-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-sm-3>*{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.row-cols-sm-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-sm-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-sm-6>*{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-sm-1{-ms-flex:0 0 8.33333%;flex:0 0 8.33333%;max-width:8.33333%}.col-sm-2{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-sm-5{-ms-flex:0 0 41.66667%;flex:0 0 41.66667%;max-width:41.66667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.33333%;flex:0 0 58.33333%;max-width:58.33333%}.col-sm-8{-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.33333%;flex:0 0 83.33333%;max-width:83.33333%}.col-sm-11{-ms-flex:0 0 91.66667%;flex:0 0 91.66667%;max-width:91.66667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-ms-flex-order:-1;order:-1}.order-sm-last{-ms-flex-order:13;order:13}.order-sm-0{-ms-flex-order:0;order:0}.order-sm-1{-ms-flex-order:1;order:1}.order-sm-2{-ms-flex-order:2;order:2}.order-sm-3{-ms-flex-order:3;order:3}.order-sm-4{-ms-flex-order:4;order:4}.order-sm-5{-ms-flex-order:5;order:5}.order-sm-6{-ms-flex-order:6;order:6}.order-sm-7{-ms-flex-order:7;order:7}.order-sm-8{-ms-flex-order:8;order:8}.order-sm-9{-ms-flex-order:9;order:9}.order-sm-10{-ms-flex-order:10;order:10}.order-sm-11{-ms-flex-order:11;order:11}.order-sm-12{-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333%}.offset-sm-2{margin-left:16.66667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333%}.offset-sm-5{margin-left:41.66667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333%}.offset-sm-8{margin-left:66.66667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333%}.offset-sm-11{margin-left:91.66667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-md-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-md-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-md-3>*{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.row-cols-md-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-md-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-md-6>*{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-md-1{-ms-flex:0 0 8.33333%;flex:0 0 8.33333%;max-width:8.33333%}.col-md-2{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-md-5{-ms-flex:0 0 41.66667%;flex:0 0 41.66667%;max-width:41.66667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.33333%;flex:0 0 58.33333%;max-width:58.33333%}.col-md-8{-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.33333%;flex:0 0 83.33333%;max-width:83.33333%}.col-md-11{-ms-flex:0 0 91.66667%;flex:0 0 91.66667%;max-width:91.66667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-ms-flex-order:-1;order:-1}.order-md-last{-ms-flex-order:13;order:13}.order-md-0{-ms-flex-order:0;order:0}.order-md-1{-ms-flex-order:1;order:1}.order-md-2{-ms-flex-order:2;order:2}.order-md-3{-ms-flex-order:3;order:3}.order-md-4{-ms-flex-order:4;order:4}.order-md-5{-ms-flex-order:5;order:5}.order-md-6{-ms-flex-order:6;order:6}.order-md-7{-ms-flex-order:7;order:7}.order-md-8{-ms-flex-order:8;order:8}.order-md-9{-ms-flex-order:9;order:9}.order-md-10{-ms-flex-order:10;order:10}.order-md-11{-ms-flex-order:11;order:11}.order-md-12{-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333%}.offset-md-2{margin-left:16.66667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333%}.offset-md-5{margin-left:41.66667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333%}.offset-md-8{margin-left:66.66667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333%}.offset-md-11{margin-left:91.66667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-lg-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-lg-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-lg-3>*{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.row-cols-lg-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-lg-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-lg-6>*{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-lg-1{-ms-flex:0 0 8.33333%;flex:0 0 8.33333%;max-width:8.33333%}.col-lg-2{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-lg-5{-ms-flex:0 0 41.66667%;flex:0 0 41.66667%;max-width:41.66667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.33333%;flex:0 0 58.33333%;max-width:58.33333%}.col-lg-8{-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.33333%;flex:0 0 83.33333%;max-width:83.33333%}.col-lg-11{-ms-flex:0 0 91.66667%;flex:0 0 91.66667%;max-width:91.66667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-ms-flex-order:-1;order:-1}.order-lg-last{-ms-flex-order:13;order:13}.order-lg-0{-ms-flex-order:0;order:0}.order-lg-1{-ms-flex-order:1;order:1}.order-lg-2{-ms-flex-order:2;order:2}.order-lg-3{-ms-flex-order:3;order:3}.order-lg-4{-ms-flex-order:4;order:4}.order-lg-5{-ms-flex-order:5;order:5}.order-lg-6{-ms-flex-order:6;order:6}.order-lg-7{-ms-flex-order:7;order:7}.order-lg-8{-ms-flex-order:8;order:8}.order-lg-9{-ms-flex-order:9;order:9}.order-lg-10{-ms-flex-order:10;order:10}.order-lg-11{-ms-flex-order:11;order:11}.order-lg-12{-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333%}.offset-lg-2{margin-left:16.66667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333%}.offset-lg-5{margin-left:41.66667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333%}.offset-lg-8{margin-left:66.66667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333%}.offset-lg-11{margin-left:91.66667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-xl-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-xl-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-xl-3>*{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.row-cols-xl-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-xl-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-xl-6>*{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-xl-1{-ms-flex:0 0 8.33333%;flex:0 0 8.33333%;max-width:8.33333%}.col-xl-2{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-xl-5{-ms-flex:0 0 41.66667%;flex:0 0 41.66667%;max-width:41.66667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.33333%;flex:0 0 58.33333%;max-width:58.33333%}.col-xl-8{-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.33333%;flex:0 0 83.33333%;max-width:83.33333%}.col-xl-11{-ms-flex:0 0 91.66667%;flex:0 0 91.66667%;max-width:91.66667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-ms-flex-order:-1;order:-1}.order-xl-last{-ms-flex-order:13;order:13}.order-xl-0{-ms-flex-order:0;order:0}.order-xl-1{-ms-flex-order:1;order:1}.order-xl-2{-ms-flex-order:2;order:2}.order-xl-3{-ms-flex-order:3;order:3}.order-xl-4{-ms-flex-order:4;order:4}.order-xl-5{-ms-flex-order:5;order:5}.order-xl-6{-ms-flex-order:6;order:6}.order-xl-7{-ms-flex-order:7;order:7}.order-xl-8{-ms-flex-order:8;order:8}.order-xl-9{-ms-flex-order:9;order:9}.order-xl-10{-ms-flex-order:10;order:10}.order-xl-11{-ms-flex-order:11;order:11}.order-xl-12{-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333%}.offset-xl-2{margin-left:16.66667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333%}.offset-xl-5{margin-left:41.66667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333%}.offset-xl-8{margin-left:66.66667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333%}.offset-xl-11{margin-left:91.66667%}}.table{width:100%;margin-bottom:1rem;color:#212529}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table-sm td,.table-sm th{padding:.3rem}.table-bordered,.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{color:#212529;background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-primary tbody+tbody,.table-primary td,.table-primary th,.table-primary thead th{border-color:#7abaff}.table-hover .table-primary:hover,.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#dddfe2}.table-secondary tbody+tbody,.table-secondary td,.table-secondary th,.table-secondary thead th{border-color:#c0c4c8}.table-hover .table-secondary:hover,.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#cfd2d6}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-success tbody+tbody,.table-success td,.table-success th,.table-success thead th{border-color:#8fd19e}.table-hover .table-success:hover,.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-info tbody+tbody,.table-info td,.table-info th,.table-info thead th{border-color:#86cfda}.table-hover .table-info:hover,.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-warning tbody+tbody,.table-warning td,.table-warning th,.table-warning thead th{border-color:#ffdf7e}.table-hover .table-warning:hover,.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-danger tbody+tbody,.table-danger td,.table-danger th,.table-danger thead th{border-color:#ed969e}.table-hover .table-danger:hover,.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-light tbody+tbody,.table-light td,.table-light th,.table-light thead th{border-color:#fbfcfc}.table-hover .table-light:hover,.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#95999c}.table-hover .table-dark:hover,.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th,.table-hover .table-active:hover,.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#343a40;border-color:#454d55}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#343a40}.table-dark td,.table-dark th,.table-dark thead th{border-color:#454d55}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:hsla(0,0%,100%,.05)}.table-dark.table-hover tbody tr:hover{color:#fff;background-color:hsla(0,0%,100%,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:-moz-focusring{color:transparent;text-shadow:0 0 0 #495057}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.form-control::-webkit-input-placeholder{color:#868e96;opacity:1}.form-control::-moz-placeholder{color:#868e96;opacity:1}.form-control:-ms-input-placeholder,.form-control::-ms-input-placeholder{color:#868e96;opacity:1}.form-control::placeholder{color:#868e96;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}input[type=date].form-control,input[type=datetime-local].form-control,input[type=month].form-control,input[type=time].form-control{-webkit-appearance:none;-moz-appearance:none;appearance:none}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;font-size:1rem;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{height:calc(1.5em + .5rem + 2px);padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.form-control-lg{height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}select.form-control[multiple],select.form-control[size],textarea.form-control{height:auto}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{color:#868e96}.form-check-label{margin-bottom:0}.form-check-inline{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;left:0;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:rgba(40,167,69,.9);border-radius:.25rem}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:#28a745;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3E%3Cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-valid,.was-validated .custom-select:valid{border-color:#28a745;padding-right:calc(.75em + 2.3125rem);background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3E%3Cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3E%3C/svg%3E") #fff no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)}.custom-select.is-valid:focus,.was-validated .custom-select:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#28a745}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#28a745}.custom-control-input.is-valid~.custom-control-label:before,.was-validated .custom-control-input:valid~.custom-control-label:before{border-color:#28a745}.custom-control-input.is-valid:checked~.custom-control-label:before,.was-validated .custom-control-input:valid:checked~.custom-control-label:before{border-color:#34ce57;background-color:#34ce57}.custom-control-input.is-valid:focus~.custom-control-label:before,.was-validated .custom-control-input:valid:focus~.custom-control-label:before{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-control-input.is-valid:focus:not(:checked)~.custom-control-label:before,.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label:before,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#28a745}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;left:0;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#dc3545;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3E%3Ccircle cx='6' cy='6' r='4.5'/%3E%3Cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3E%3Ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-invalid,.was-validated .custom-select:invalid{border-color:#dc3545;padding-right:calc(.75em + 2.3125rem);background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3E%3Ccircle cx='6' cy='6' r='4.5'/%3E%3Cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3E%3Ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3E%3C/svg%3E") #fff no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)}.custom-select.is-invalid:focus,.was-validated .custom-select:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-label:before,.was-validated .custom-control-input:invalid~.custom-control-label:before{border-color:#dc3545}.custom-control-input.is-invalid:checked~.custom-control-label:before,.was-validated .custom-control-input:invalid:checked~.custom-control-label:before{border-color:#e4606d;background-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label:before,.was-validated .custom-control-input:invalid:focus~.custom-control-label:before{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-control-input.is-invalid:focus:not(:checked)~.custom-control-label:before,.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label:before,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{-ms-flex-align:center;-ms-flex-pack:center;justify-content:center}.form-inline .form-group,.form-inline label{display:-ms-flexbox;display:flex;align-items:center;margin-bottom:0}.form-inline .form-group{-ms-flex:0 0 auto;flex:0 0 auto;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .custom-select,.form-inline .input-group{width:auto}.form-inline .form-check{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;-ms-flex-negative:0;flex-shrink:0;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;color:#212529;text-align:center;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529;text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary.focus,.btn-primary:focus,.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 .2rem rgba(38,143,255,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(38,143,255,.5)}.btn-secondary{color:#fff;background-color:#868e96;border-color:#868e96}.btn-secondary.focus,.btn-secondary:focus,.btn-secondary:hover{color:#fff;background-color:#727b84;border-color:#6c757d}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 .2rem hsla(210,7%,62%,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#868e96;border-color:#868e96}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#666e76}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem hsla(210,7%,62%,.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success.focus,.btn-success:focus,.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 .2rem rgba(72,180,97,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(72,180,97,.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info.focus,.btn-info:focus,.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 .2rem rgba(58,176,195,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(58,176,195,.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning.focus,.btn-warning:focus,.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 .2rem rgba(222,170,12,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(222,170,12,.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger.focus,.btn-danger:focus,.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 .2rem rgba(225,83,97,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(225,83,97,.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light.focus,.btn-light:focus,.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 .2rem hsla(220,4%,85%,.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem hsla(220,4%,85%,.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark.focus,.btn-dark:focus,.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 .2rem rgba(82,88,93,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(82,88,93,.5)}.btn-outline-primary{color:#007bff;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-secondary{color:#868e96;border-color:#868e96}.btn-outline-secondary:hover{color:#fff;background-color:#868e96;border-color:#868e96}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem hsla(210,7%,56%,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#868e96;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#868e96;border-color:#868e96}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem hsla(210,7%,56%,.5)}.btn-outline-success{color:#28a745;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-info{color:#17a2b8;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-warning{color:#ffc107;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-danger{color:#dc3545;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-dark{color:#343a40;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-link{font-weight:400;color:#007bff;text-decoration:none}.btn-link:hover{color:#0056b3}.btn-link.focus,.btn-link:focus,.btn-link:hover{text-decoration:underline}.btn-link.disabled,.btn-link:disabled{color:#868e96;pointer-events:none}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropleft,.dropright,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty:after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu-left{right:auto;left:0}.dropdown-menu-right{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-left{right:auto;left:0}.dropdown-menu-sm-right{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-left{right:auto;left:0}.dropdown-menu-md-right{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-left{right:auto;left:0}.dropdown-menu-lg-right{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-left{right:auto;left:0}.dropdown-menu-xl-right{right:0;left:auto}}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty:after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty:after{margin-left:0}.dropright .dropdown-toggle:after{vertical-align:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";display:none}.dropleft .dropdown-toggle:before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty:after{margin-left:0}.dropleft .dropdown-toggle:before{vertical-align:0}.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=top]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#868e96;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#868e96;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#212529}.btn-group,.btn-group-vertical{position:relative;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-ms-flex:1 1 auto;flex:1 1 auto}.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:1}.btn-toolbar{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split:after,.dropright .dropdown-toggle-split:after,.dropup .dropdown-toggle-split:after{margin-left:0}.dropleft .dropdown-toggle-split:before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:center;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio],.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:stretch;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control,.input-group>.form-control-plaintext{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;min-width:0;margin-bottom:0}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control,.input-group>.form-control-plaintext+.custom-file,.input-group>.form-control-plaintext+.custom-select,.input-group>.form-control-plaintext+.form-control{margin-left:-1px}.input-group>.custom-file .custom-file-input:focus~.custom-file-label,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file .custom-file-input:focus{z-index:4}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label:after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:-ms-flexbox;display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn:focus,.input-group-prepend .btn:focus{z-index:3}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group-lg>.custom-select,.input-group-lg>.form-control:not(textarea){height:calc(1.5em + 1rem + 2px)}.input-group-lg>.custom-select,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-sm>.custom-select,.input-group-sm>.form-control:not(textarea){height:calc(1.5em + .5rem + 2px)}.input-group-sm>.custom-select,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-lg>.custom-select,.input-group-sm>.custom-select{padding-right:1.75rem}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;z-index:1;display:block;min-height:1.5rem;padding-left:1.5rem;color-adjust:exact}.custom-control-inline{display:-ms-inline-flexbox;display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;left:0;z-index:-1;width:1rem;height:1.25rem;opacity:0}.custom-control-input:checked~.custom-control-label:before{color:#fff;border-color:#007bff;background-color:#007bff}.custom-control-input:focus~.custom-control-label:before{box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-control-input:focus:not(:checked)~.custom-control-label:before{border-color:#80bdff}.custom-control-input:not(:disabled):active~.custom-control-label:before{color:#fff;background-color:#b3d7ff;border-color:#b3d7ff}.custom-control-input:disabled~.custom-control-label,.custom-control-input[disabled]~.custom-control-label{color:#868e96}.custom-control-input:disabled~.custom-control-label:before,.custom-control-input[disabled]~.custom-control-label:before{background-color:#e9ecef}.custom-control-label{position:relative;margin-bottom:0;vertical-align:top}.custom-control-label:before{pointer-events:none;background-color:#fff;border:1px solid #adb5bd}.custom-control-label:after,.custom-control-label:before{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:""}.custom-control-label:after{background:no-repeat 50%/50% 50%}.custom-checkbox .custom-control-label:before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label:after{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label:before{border-color:#007bff;background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label:after{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label:before{background-color:rgba(0,123,255,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label:before{background-color:rgba(0,123,255,.5)}.custom-radio .custom-control-label:before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label:after{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label:before{background-color:rgba(0,123,255,.5)}.custom-switch{padding-left:2.25rem}.custom-switch .custom-control-label:before{left:-2.25rem;width:1.75rem;pointer-events:all;border-radius:.5rem}.custom-switch .custom-control-label:after{top:calc(.25rem + 2px);left:calc(-2.25rem + 2px);width:calc(1rem - 4px);height:calc(1rem - 4px);background-color:#adb5bd;border-radius:.5rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-switch .custom-control-label:after{transition:none}}.custom-switch .custom-control-input:checked~.custom-control-label:after{background-color:#fff;-webkit-transform:translateX(.75rem);transform:translateX(.75rem)}.custom-switch .custom-control-input:disabled:checked~.custom-control-label:before{background-color:rgba(0,123,255,.5)}.custom-select{display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem 1.75rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center/8px 10px;border:1px solid #ced4da;border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#868e96;background-color:#e9ecef}.custom-select::-ms-expand{display:none}.custom-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #495057}.custom-select-sm{height:calc(1.5em + .5rem + 2px);padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem}.custom-select-lg{height:calc(1.5em + 1rem + 2px);padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.custom-file{display:inline-block;margin-bottom:0}.custom-file,.custom-file-input{position:relative;width:100%;height:calc(1.5em + .75rem + 2px)}.custom-file-input{z-index:2;margin:0;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-file-input:disabled~.custom-file-label,.custom-file-input[disabled]~.custom-file-label{background-color:#e9ecef}.custom-file-input:lang(en)~.custom-file-label:after{content:"Browse"}.custom-file-input~.custom-file-label[data-browse]:after{content:attr(data-browse)}.custom-file-label{left:0;z-index:1;height:calc(1.5em + .75rem + 2px);font-weight:400;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label,.custom-file-label:after{position:absolute;top:0;right:0;padding:.375rem .75rem;line-height:1.5;color:#495057}.custom-file-label:after{bottom:0;z-index:3;display:block;height:calc(1.5em + .75rem);content:"Browse";background-color:#e9ecef;border-left:inherit;border-radius:0 .25rem .25rem 0}.custom-range{width:100%;height:1.4rem;padding:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-range:focus{outline:none}.custom-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range:focus::-ms-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-webkit-slider-thumb{transition:none}}.custom-range::-webkit-slider-thumb:active{background-color:#b3d7ff}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-moz-range-thumb{transition:none}}.custom-range::-moz-range-thumb:active{background-color:#b3d7ff}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-ms-thumb{width:1rem;height:1rem;margin-top:0;margin-right:.2rem;margin-left:.2rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-ms-thumb{transition:none}}.custom-range::-ms-thumb:active{background-color:#b3d7ff}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem}.custom-range::-ms-fill-lower,.custom-range::-ms-fill-upper{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:15px}.custom-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.custom-range:disabled::-webkit-slider-runnable-track{cursor:default}.custom-range:disabled::-moz-range-thumb{background-color:#adb5bd}.custom-range:disabled::-moz-range-track{cursor:default}.custom-range:disabled::-ms-thumb{background-color:#adb5bd}.custom-control-label:before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-control-label:before,.custom-file-label,.custom-select{transition:none}}.nav{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#868e96;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#868e96;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item,.nav-fill>.nav-link{-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;padding:.5rem 1rem}.navbar,.navbar .container,.navbar .container-fluid,.navbar .container-lg,.navbar .container-md,.navbar .container-sm,.navbar .container-xl{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat 50%;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-xl{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-md,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-xl{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-md,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-xl{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-xl{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-lg,.navbar-expand>.container-md,.navbar-expand>.container-sm,.navbar-expand>.container-xl{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-lg,.navbar-expand>.container-md,.navbar-expand>.container-sm,.navbar-expand>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand,.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a,.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand,.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:hsla(0,0%,100%,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:hsla(0,0%,100%,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:hsla(0,0%,100%,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:hsla(0,0%,100%,.5);border-color:hsla(0,0%,100%,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:hsla(0,0%,100%,.5)}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{-ms-flex:1 1 auto;flex:1 1 auto;min-height:1px;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem}.card-subtitle,.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-bottom:-.75rem;border-bottom:0}.card-header-pills,.card-header-tabs{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem;border-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom,.card-img-top{-ms-flex-negative:0;flex-shrink:0;width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{-ms-flex:1 0 0%;flex:1 0 0%;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group>.card{-ms-flex:1 0 0%;flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.accordion{overflow-anchor:none}.accordion>.card{overflow:hidden}.accordion>.card:not(:last-of-type){border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion>.card:not(:first-of-type){border-top-left-radius:0;border-top-right-radius:0}.accordion>.card>.card-header{border-radius:0;margin-bottom:-1px}.breadcrumb{-ms-flex-wrap:wrap;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb,.breadcrumb-item{display:-ms-flexbox;display:flex}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item:before{display:inline-block;padding-right:.5rem;color:#868e96;content:"/"}.breadcrumb-item+.breadcrumb-item:hover:before{text-decoration:underline;text-decoration:none}.breadcrumb-item.active{color:#868e96}.pagination{display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{z-index:2;color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:3;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#868e96;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.badge{transition:none}}a.badge:focus,a.badge:hover{text-decoration:none}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}a.badge-primary:focus,a.badge-primary:hover{color:#fff;background-color:#0062cc}a.badge-primary.focus,a.badge-primary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.badge-secondary{color:#fff;background-color:#868e96}a.badge-secondary:focus,a.badge-secondary:hover{color:#fff;background-color:#6c757d}a.badge-secondary.focus,a.badge-secondary:focus{outline:0;box-shadow:0 0 0 .2rem hsla(210,7%,56%,.5)}.badge-success{color:#fff;background-color:#28a745}a.badge-success:focus,a.badge-success:hover{color:#fff;background-color:#1e7e34}a.badge-success.focus,a.badge-success:focus{outline:0;box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.badge-info{color:#fff;background-color:#17a2b8}a.badge-info:focus,a.badge-info:hover{color:#fff;background-color:#117a8b}a.badge-info.focus,a.badge-info:focus{outline:0;box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.badge-warning{color:#212529;background-color:#ffc107}a.badge-warning:focus,a.badge-warning:hover{color:#212529;background-color:#d39e00}a.badge-warning.focus,a.badge-warning:focus{outline:0;box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.badge-danger{color:#fff;background-color:#dc3545}a.badge-danger:focus,a.badge-danger:hover{color:#fff;background-color:#bd2130}a.badge-danger.focus,a.badge-danger:focus{outline:0;box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.badge-light{color:#212529;background-color:#f8f9fa}a.badge-light:focus,a.badge-light:hover{color:#212529;background-color:#dae0e5}a.badge-light.focus,a.badge-light:focus{outline:0;box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.badge-dark{color:#fff;background-color:#343a40}a.badge-dark:focus,a.badge-dark:hover{color:#fff;background-color:#1d2124}a.badge-dark.focus,a.badge-dark:focus{outline:0;box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;z-index:2;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#464a4e;background-color:#e7e8ea;border-color:#dddfe2}.alert-secondary hr{border-top-color:#cfd2d6}.alert-secondary .alert-link{color:#2e3133}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes a{0%{background-position:1rem 0}to{background-position:0 0}}@keyframes a{0%{background-position:1rem 0}to{background-position:0 0}}.progress{height:1rem;line-height:0;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress,.progress-bar{display:-ms-flexbox;display:flex;overflow:hidden}.progress-bar{-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;color:#fff;text-align:center;white-space:nowrap;background-color:#007bff;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 0,transparent 50%,hsla(0,0%,100%,.15) 0,hsla(0,0%,100%,.15) 75%,transparent 0,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:a 1s linear infinite;animation:a 1s linear infinite}@media (prefers-reduced-motion:reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.media{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start}.media-body{-ms-flex:1;flex:1}.list-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#868e96;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media (min-width:576px){.list-group-horizontal-sm{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:768px){.list-group-horizontal-md{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:992px){.list-group-horizontal-lg{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1200px){.list-group-horizontal-xl{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#464a4e;background-color:#dddfe2}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#464a4e;background-color:#cfd2d6}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#464a4e;border-color:#464a4e}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:hover{color:#000;text-decoration:none}.close:not(:disabled):not(.disabled):focus,.close:not(:disabled):not(.disabled):hover{opacity:.75}button.close{padding:0;background-color:transparent;border:0}a.close.disabled{pointer-events:none}.toast{-ms-flex-preferred-size:350px;flex-basis:350px;max-width:350px;font-size:.875rem;background-color:hsla(0,0%,100%,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .25rem .75rem rgba(0,0,0,.1);opacity:0;border-radius:.25rem}.toast:not(:last-child){margin-bottom:.75rem}.toast.showing{opacity:1}.toast.show{display:block;opacity:1}.toast.hide{display:none}.toast-header{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.25rem .75rem;color:#868e96;background-color:hsla(0,0%,100%,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05);border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.toast-body{padding:.75rem}.modal-open{overflow:hidden}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal{position:fixed;top:0;left:0;z-index:1050;display:none;width:100%;height:100%;overflow:hidden;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translateY(-50px);transform:translateY(-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{-webkit-transform:none;transform:none}.modal.modal-static .modal-dialog{-webkit-transform:scale(1.02);transform:scale(1.02)}.modal-dialog-scrollable{display:-ms-flexbox;display:flex;max-height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 1rem);overflow:hidden}.modal-dialog-scrollable .modal-footer,.modal-dialog-scrollable .modal-header{-ms-flex-negative:0;flex-shrink:0}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;min-height:calc(100% - 1rem)}.modal-dialog-centered:before{display:block;height:calc(100vh - 1rem);height:-webkit-min-content;height:-moz-min-content;height:min-content;content:""}.modal-dialog-centered.modal-dialog-scrollable{-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;height:100%}.modal-dialog-centered.modal-dialog-scrollable .modal-content{max-height:none}.modal-dialog-centered.modal-dialog-scrollable:before{content:none}.modal-content{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:justify;justify-content:space-between;padding:1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.modal-header .close{padding:1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-footer{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:end;justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6;border-bottom-right-radius:calc(.3rem - 1px);border-bottom-left-radius:calc(.3rem - 1px)}.modal-footer>*{margin:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{max-height:calc(100% - 3.5rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-dialog-centered:before{height:calc(100vh - 3.5rem);height:-webkit-min-content;height:-moz-min-content;height:min-content}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif;font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow:before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow:before,.bs-tooltip-top .arrow:before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow:before,.bs-tooltip-right .arrow:before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow:before,.bs-tooltip-bottom .arrow:before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow:before,.bs-tooltip-left .arrow:before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{top:0;left:0;z-index:1060;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif;font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover,.popover .arrow{position:absolute;display:block}.popover .arrow{width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow:after,.popover .arrow:before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top]>.arrow,.bs-popover-top>.arrow{bottom:calc(-.5rem - 1px)}.bs-popover-auto[x-placement^=top]>.arrow:before,.bs-popover-top>.arrow:before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top]>.arrow:after,.bs-popover-top>.arrow:after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right]>.arrow,.bs-popover-right>.arrow{left:calc(-.5rem - 1px);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right]>.arrow:before,.bs-popover-right>.arrow:before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right]>.arrow:after,.bs-popover-right>.arrow:after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom]>.arrow,.bs-popover-bottom>.arrow{top:calc(-.5rem - 1px)}.bs-popover-auto[x-placement^=bottom]>.arrow:before,.bs-popover-bottom>.arrow:before{top:0;border-width:0 .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom]>.arrow:after,.bs-popover-bottom>.arrow:after{top:1px;border-width:0 .5rem .5rem;border-bottom-color:#fff}.bs-popover-auto[x-placement^=bottom] .popover-header:before,.bs-popover-bottom .popover-header:before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left]>.arrow,.bs-popover-left>.arrow{right:calc(-.5rem - 1px);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left]>.arrow:before,.bs-popover-left>.arrow:before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left]>.arrow:after,.bs-popover-left>.arrow:after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{-ms-touch-action:pan-y;touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner:after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:-webkit-transform .6s ease-in-out;transition:transform .6s ease-in-out;transition:transform .6s ease-in-out,-webkit-transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-right,.carousel-item-next:not(.carousel-item-left){-webkit-transform:translateX(100%);transform:translateX(100%)}.active.carousel-item-left,.carousel-item-prev:not(.carousel-item-right){-webkit-transform:translateX(-100%);transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;-webkit-transform:none;transform:none}.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:no-repeat 50%/100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5L3.75 4l-2.5 2.5L2.75 8l4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:15;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{box-sizing:content-box;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators li{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}@-webkit-keyframes b{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes b{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;-webkit-animation:b .75s linear infinite;animation:b .75s linear infinite}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@-webkit-keyframes c{0%{-webkit-transform:scale(0);transform:scale(0)}50%{opacity:1;-webkit-transform:none;transform:none}}@keyframes c{0%{-webkit-transform:scale(0);transform:scale(0)}50%{opacity:1;-webkit-transform:none;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;background-color:currentColor;border-radius:50%;opacity:0;-webkit-animation:c .75s linear infinite;animation:c .75s linear infinite}.spinner-grow-sm{width:1rem;height:1rem}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#868e96!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#6c757d!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#868e96!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded-sm{border-radius:.2rem!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important}.rounded-right,.rounded-top{border-top-right-radius:.25rem!important}.rounded-bottom,.rounded-right{border-bottom-right-radius:.25rem!important}.rounded-bottom,.rounded-left{border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important}.rounded-lg{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-0{border-radius:0!important}.clearfix:after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive:before{display:block;content:""}.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-21by9:before{padding-top:42.85714%}.embed-responsive-16by9:before{padding-top:56.25%}.embed-responsive-4by3:before{padding-top:75%}.embed-responsive-1by1:before{padding-top:100%}.flex-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-sm-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-sm-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-sm-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-sm-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-sm-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-sm-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-md-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-md-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-md-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-md-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-md-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-md-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-lg-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-lg-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-lg-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-lg-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-lg-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-lg-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-xl-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-xl-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-xl-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-xl-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-xl-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-xl-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;-ms-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;-ms-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;-ms-user-select:none!important;user-select:none!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{top:0}.fixed-bottom,.fixed-top{position:fixed;right:0;left:0;z-index:1030}.fixed-bottom{bottom:0}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.min-vw-100{min-width:100vw!important}.min-vh-100{min-height:100vh!important}.vw-100{width:100vw!important}.vh-100{height:100vh!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-n1{margin:-.25rem!important}.mt-n1,.my-n1{margin-top:-.25rem!important}.mr-n1,.mx-n1{margin-right:-.25rem!important}.mb-n1,.my-n1{margin-bottom:-.25rem!important}.ml-n1,.mx-n1{margin-left:-.25rem!important}.m-n2{margin:-.5rem!important}.mt-n2,.my-n2{margin-top:-.5rem!important}.mr-n2,.mx-n2{margin-right:-.5rem!important}.mb-n2,.my-n2{margin-bottom:-.5rem!important}.ml-n2,.mx-n2{margin-left:-.5rem!important}.m-n3{margin:-1rem!important}.mt-n3,.my-n3{margin-top:-1rem!important}.mr-n3,.mx-n3{margin-right:-1rem!important}.mb-n3,.my-n3{margin-bottom:-1rem!important}.ml-n3,.mx-n3{margin-left:-1rem!important}.m-n4{margin:-1.5rem!important}.mt-n4,.my-n4{margin-top:-1.5rem!important}.mr-n4,.mx-n4{margin-right:-1.5rem!important}.mb-n4,.my-n4{margin-bottom:-1.5rem!important}.ml-n4,.mx-n4{margin-left:-1.5rem!important}.m-n5{margin:-3rem!important}.mt-n5,.my-n5{margin-top:-3rem!important}.mr-n5,.mx-n5{margin-right:-3rem!important}.mb-n5,.my-n5{margin-bottom:-3rem!important}.ml-n5,.mx-n5{margin-left:-3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-n1{margin:-.25rem!important}.mt-sm-n1,.my-sm-n1{margin-top:-.25rem!important}.mr-sm-n1,.mx-sm-n1{margin-right:-.25rem!important}.mb-sm-n1,.my-sm-n1{margin-bottom:-.25rem!important}.ml-sm-n1,.mx-sm-n1{margin-left:-.25rem!important}.m-sm-n2{margin:-.5rem!important}.mt-sm-n2,.my-sm-n2{margin-top:-.5rem!important}.mr-sm-n2,.mx-sm-n2{margin-right:-.5rem!important}.mb-sm-n2,.my-sm-n2{margin-bottom:-.5rem!important}.ml-sm-n2,.mx-sm-n2{margin-left:-.5rem!important}.m-sm-n3{margin:-1rem!important}.mt-sm-n3,.my-sm-n3{margin-top:-1rem!important}.mr-sm-n3,.mx-sm-n3{margin-right:-1rem!important}.mb-sm-n3,.my-sm-n3{margin-bottom:-1rem!important}.ml-sm-n3,.mx-sm-n3{margin-left:-1rem!important}.m-sm-n4{margin:-1.5rem!important}.mt-sm-n4,.my-sm-n4{margin-top:-1.5rem!important}.mr-sm-n4,.mx-sm-n4{margin-right:-1.5rem!important}.mb-sm-n4,.my-sm-n4{margin-bottom:-1.5rem!important}.ml-sm-n4,.mx-sm-n4{margin-left:-1.5rem!important}.m-sm-n5{margin:-3rem!important}.mt-sm-n5,.my-sm-n5{margin-top:-3rem!important}.mr-sm-n5,.mx-sm-n5{margin-right:-3rem!important}.mb-sm-n5,.my-sm-n5{margin-bottom:-3rem!important}.ml-sm-n5,.mx-sm-n5{margin-left:-3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-n1{margin:-.25rem!important}.mt-md-n1,.my-md-n1{margin-top:-.25rem!important}.mr-md-n1,.mx-md-n1{margin-right:-.25rem!important}.mb-md-n1,.my-md-n1{margin-bottom:-.25rem!important}.ml-md-n1,.mx-md-n1{margin-left:-.25rem!important}.m-md-n2{margin:-.5rem!important}.mt-md-n2,.my-md-n2{margin-top:-.5rem!important}.mr-md-n2,.mx-md-n2{margin-right:-.5rem!important}.mb-md-n2,.my-md-n2{margin-bottom:-.5rem!important}.ml-md-n2,.mx-md-n2{margin-left:-.5rem!important}.m-md-n3{margin:-1rem!important}.mt-md-n3,.my-md-n3{margin-top:-1rem!important}.mr-md-n3,.mx-md-n3{margin-right:-1rem!important}.mb-md-n3,.my-md-n3{margin-bottom:-1rem!important}.ml-md-n3,.mx-md-n3{margin-left:-1rem!important}.m-md-n4{margin:-1.5rem!important}.mt-md-n4,.my-md-n4{margin-top:-1.5rem!important}.mr-md-n4,.mx-md-n4{margin-right:-1.5rem!important}.mb-md-n4,.my-md-n4{margin-bottom:-1.5rem!important}.ml-md-n4,.mx-md-n4{margin-left:-1.5rem!important}.m-md-n5{margin:-3rem!important}.mt-md-n5,.my-md-n5{margin-top:-3rem!important}.mr-md-n5,.mx-md-n5{margin-right:-3rem!important}.mb-md-n5,.my-md-n5{margin-bottom:-3rem!important}.ml-md-n5,.mx-md-n5{margin-left:-3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-n1{margin:-.25rem!important}.mt-lg-n1,.my-lg-n1{margin-top:-.25rem!important}.mr-lg-n1,.mx-lg-n1{margin-right:-.25rem!important}.mb-lg-n1,.my-lg-n1{margin-bottom:-.25rem!important}.ml-lg-n1,.mx-lg-n1{margin-left:-.25rem!important}.m-lg-n2{margin:-.5rem!important}.mt-lg-n2,.my-lg-n2{margin-top:-.5rem!important}.mr-lg-n2,.mx-lg-n2{margin-right:-.5rem!important}.mb-lg-n2,.my-lg-n2{margin-bottom:-.5rem!important}.ml-lg-n2,.mx-lg-n2{margin-left:-.5rem!important}.m-lg-n3{margin:-1rem!important}.mt-lg-n3,.my-lg-n3{margin-top:-1rem!important}.mr-lg-n3,.mx-lg-n3{margin-right:-1rem!important}.mb-lg-n3,.my-lg-n3{margin-bottom:-1rem!important}.ml-lg-n3,.mx-lg-n3{margin-left:-1rem!important}.m-lg-n4{margin:-1.5rem!important}.mt-lg-n4,.my-lg-n4{margin-top:-1.5rem!important}.mr-lg-n4,.mx-lg-n4{margin-right:-1.5rem!important}.mb-lg-n4,.my-lg-n4{margin-bottom:-1.5rem!important}.ml-lg-n4,.mx-lg-n4{margin-left:-1.5rem!important}.m-lg-n5{margin:-3rem!important}.mt-lg-n5,.my-lg-n5{margin-top:-3rem!important}.mr-lg-n5,.mx-lg-n5{margin-right:-3rem!important}.mb-lg-n5,.my-lg-n5{margin-bottom:-3rem!important}.ml-lg-n5,.mx-lg-n5{margin-left:-3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-n1{margin:-.25rem!important}.mt-xl-n1,.my-xl-n1{margin-top:-.25rem!important}.mr-xl-n1,.mx-xl-n1{margin-right:-.25rem!important}.mb-xl-n1,.my-xl-n1{margin-bottom:-.25rem!important}.ml-xl-n1,.mx-xl-n1{margin-left:-.25rem!important}.m-xl-n2{margin:-.5rem!important}.mt-xl-n2,.my-xl-n2{margin-top:-.5rem!important}.mr-xl-n2,.mx-xl-n2{margin-right:-.5rem!important}.mb-xl-n2,.my-xl-n2{margin-bottom:-.5rem!important}.ml-xl-n2,.mx-xl-n2{margin-left:-.5rem!important}.m-xl-n3{margin:-1rem!important}.mt-xl-n3,.my-xl-n3{margin-top:-1rem!important}.mr-xl-n3,.mx-xl-n3{margin-right:-1rem!important}.mb-xl-n3,.my-xl-n3{margin-bottom:-1rem!important}.ml-xl-n3,.mx-xl-n3{margin-left:-1rem!important}.m-xl-n4{margin:-1.5rem!important}.mt-xl-n4,.my-xl-n4{margin-top:-1.5rem!important}.mr-xl-n4,.mx-xl-n4{margin-right:-1.5rem!important}.mb-xl-n4,.my-xl-n4{margin-bottom:-1.5rem!important}.ml-xl-n4,.mx-xl-n4{margin-left:-1.5rem!important}.m-xl-n5{margin:-3rem!important}.mt-xl-n5,.my-xl-n5{margin-top:-3rem!important}.mr-xl-n5,.mx-xl-n5{margin-right:-3rem!important}.mb-xl-n5,.my-xl-n5{margin-bottom:-3rem!important}.ml-xl-n5,.mx-xl-n5{margin-left:-3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.stretched-link:after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;pointer-events:auto;content:"";background-color:transparent}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace!important}.text-justify{text-align:justify!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-lighter{font-weight:lighter!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-weight-bolder{font-weight:bolder!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0056b3!important}.text-secondary{color:#868e96!important}a.text-secondary:focus,a.text-secondary:hover{color:#60686f!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#19692c!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#0f6674!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#ba8b00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#a71d2a!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#cbd3da!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#121416!important}.text-body{color:#212529!important}.text-muted{color:#868e96!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:hsla(0,0%,100%,.5)!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.text-decoration-none{text-decoration:none!important}.text-break{word-break:break-word!important;word-wrap:break-word!important}.text-reset{color:inherit!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,:after,:before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]:after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #adb5bd;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}.container,body{min-width:992px!important}.navbar{display:none}.badge{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 #dee2e6!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#dee2e6}.table .thead-dark th{color:inherit;border-color:#dee2e6}}body,h1,h2,h3,h4,h5,h6{font-family:Lato,Helvetica Neue,Helvetica,Arial,sans-serif}h1,h2,h3,h4,h5,h6{font-weight:700}header.masthead{position:relative;background-color:#343a40;background-size:cover;padding-top:8rem;padding-bottom:8rem}header.masthead .overlay{position:absolute;background-color:#212529;height:100%;width:100%;top:0;left:0;opacity:.3}header.masthead h1{font-size:2rem}@media (min-width:768px){header.masthead{padding-top:12rem;padding-bottom:12rem}header.masthead h1{font-size:3rem}}.showcase .showcase-text{padding:3rem}.showcase .showcase-img{min-height:30rem;background-size:cover}@media (min-width:768px){.showcase .showcase-text{padding:7rem}}.features-icons{padding-top:7rem;padding-bottom:7rem}.features-icons .features-icons-item{max-width:20rem}.features-icons .features-icons-item .features-icons-icon{height:7rem}.features-icons .features-icons-item .features-icons-icon i{font-size:4.5rem}.testimonials{padding-top:7rem;padding-bottom:7rem}.testimonials .testimonial-item{max-width:18rem}.testimonials .testimonial-item img{max-width:12rem;box-shadow:0 5px 5px 0 #adb5bd}.call-to-action{position:relative;background-color:#343a40;background-size:cover;padding-top:7rem;padding-bottom:7rem}.call-to-action .overlay{position:absolute;background-color:#212529;height:100%;width:100%;top:0;left:0;opacity:.3}footer.footer{padding-top:4rem;padding-bottom:4rem} \ No newline at end of file diff --git a/static/kevin-master/assets/bootstrap/js/bootstrap.min.js b/static/kevin-master/assets/bootstrap/js/bootstrap.min.js deleted file mode 100644 index ef603da..0000000 --- a/static/kevin-master/assets/bootstrap/js/bootstrap.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v4.5.3 (https://getbootstrap.com/) - * Copyright 2011-2020 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery")):"function"==typeof define&&define.amd?define(["exports","jquery"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap={},t.jQuery)}(this,(function(t,e){"use strict";function n(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var i=n(e);function o(t,e){for(var n=0;n=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}};l.jQueryDetection(),i.default.fn.emulateTransitionEnd=s,i.default.event.special[l.TRANSITION_END]={bindType:"transitionend",delegateType:"transitionend",handle:function(t){if(i.default(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}};var u="alert",f=i.default.fn[u],d=function(){function t(t){this._element=t}var e=t.prototype;return e.close=function(t){var e=this._element;t&&(e=this._getRootElement(t)),this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.dispose=function(){i.default.removeData(this._element,"bs.alert"),this._element=null},e._getRootElement=function(t){var e=l.getSelectorFromElement(t),n=!1;return e&&(n=document.querySelector(e)),n||(n=i.default(t).closest(".alert")[0]),n},e._triggerCloseEvent=function(t){var e=i.default.Event("close.bs.alert");return i.default(t).trigger(e),e},e._removeElement=function(t){var e=this;if(i.default(t).removeClass("show"),i.default(t).hasClass("fade")){var n=l.getTransitionDurationFromElement(t);i.default(t).one(l.TRANSITION_END,(function(n){return e._destroyElement(t,n)})).emulateTransitionEnd(n)}else this._destroyElement(t)},e._destroyElement=function(t){i.default(t).detach().trigger("closed.bs.alert").remove()},t._jQueryInterface=function(e){return this.each((function(){var n=i.default(this),o=n.data("bs.alert");o||(o=new t(this),n.data("bs.alert",o)),"close"===e&&o[e](this)}))},t._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},r(t,null,[{key:"VERSION",get:function(){return"4.5.3"}}]),t}();i.default(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',d._handleDismiss(new d)),i.default.fn[u]=d._jQueryInterface,i.default.fn[u].Constructor=d,i.default.fn[u].noConflict=function(){return i.default.fn[u]=f,d._jQueryInterface};var c=i.default.fn.button,h=function(){function t(t){this._element=t,this.shouldAvoidTriggerChange=!1}var e=t.prototype;return e.toggle=function(){var t=!0,e=!0,n=i.default(this._element).closest('[data-toggle="buttons"]')[0];if(n){var o=this._element.querySelector('input:not([type="hidden"])');if(o){if("radio"===o.type)if(o.checked&&this._element.classList.contains("active"))t=!1;else{var r=n.querySelector(".active");r&&i.default(r).removeClass("active")}t&&("checkbox"!==o.type&&"radio"!==o.type||(o.checked=!this._element.classList.contains("active")),this.shouldAvoidTriggerChange||i.default(o).trigger("change")),o.focus(),e=!1}}this._element.hasAttribute("disabled")||this._element.classList.contains("disabled")||(e&&this._element.setAttribute("aria-pressed",!this._element.classList.contains("active")),t&&i.default(this._element).toggleClass("active"))},e.dispose=function(){i.default.removeData(this._element,"bs.button"),this._element=null},t._jQueryInterface=function(e,n){return this.each((function(){var o=i.default(this),r=o.data("bs.button");r||(r=new t(this),o.data("bs.button",r)),r.shouldAvoidTriggerChange=n,"toggle"===e&&r[e]()}))},r(t,null,[{key:"VERSION",get:function(){return"4.5.3"}}]),t}();i.default(document).on("click.bs.button.data-api",'[data-toggle^="button"]',(function(t){var e=t.target,n=e;if(i.default(e).hasClass("btn")||(e=i.default(e).closest(".btn")[0]),!e||e.hasAttribute("disabled")||e.classList.contains("disabled"))t.preventDefault();else{var o=e.querySelector('input:not([type="hidden"])');if(o&&(o.hasAttribute("disabled")||o.classList.contains("disabled")))return void t.preventDefault();"INPUT"!==n.tagName&&"LABEL"===e.tagName||h._jQueryInterface.call(i.default(e),"toggle","INPUT"===n.tagName)}})).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',(function(t){var e=i.default(t.target).closest(".btn")[0];i.default(e).toggleClass("focus",/^focus(in)?$/.test(t.type))})),i.default(window).on("load.bs.button.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-toggle="buttons"] .btn')),e=0,n=t.length;e0,this._pointerEvent=Boolean(window.PointerEvent||window.MSPointerEvent),this._addEventListeners()}var e=t.prototype;return e.next=function(){this._isSliding||this._slide("next")},e.nextWhenVisible=function(){var t=i.default(this._element);!document.hidden&&t.is(":visible")&&"hidden"!==t.css("visibility")&&this.next()},e.prev=function(){this._isSliding||this._slide("prev")},e.pause=function(t){t||(this._isPaused=!0),this._element.querySelector(".carousel-item-next, .carousel-item-prev")&&(l.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},e.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},e.to=function(t){var e=this;this._activeElement=this._element.querySelector(".active.carousel-item");var n=this._getItemIndex(this._activeElement);if(!(t>this._items.length-1||t<0))if(this._isSliding)i.default(this._element).one("slid.bs.carousel",(function(){return e.to(t)}));else{if(n===t)return this.pause(),void this.cycle();var o=t>n?"next":"prev";this._slide(o,this._items[t])}},e.dispose=function(){i.default(this._element).off(m),i.default.removeData(this._element,"bs.carousel"),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},e._getConfig=function(t){return t=a({},v,t),l.typeCheckConfig(p,t,_),t},e._handleSwipe=function(){var t=Math.abs(this.touchDeltaX);if(!(t<=40)){var e=t/this.touchDeltaX;this.touchDeltaX=0,e>0&&this.prev(),e<0&&this.next()}},e._addEventListeners=function(){var t=this;this._config.keyboard&&i.default(this._element).on("keydown.bs.carousel",(function(e){return t._keydown(e)})),"hover"===this._config.pause&&i.default(this._element).on("mouseenter.bs.carousel",(function(e){return t.pause(e)})).on("mouseleave.bs.carousel",(function(e){return t.cycle(e)})),this._config.touch&&this._addTouchEventListeners()},e._addTouchEventListeners=function(){var t=this;if(this._touchSupported){var e=function(e){t._pointerEvent&&b[e.originalEvent.pointerType.toUpperCase()]?t.touchStartX=e.originalEvent.clientX:t._pointerEvent||(t.touchStartX=e.originalEvent.touches[0].clientX)},n=function(e){t._pointerEvent&&b[e.originalEvent.pointerType.toUpperCase()]&&(t.touchDeltaX=e.originalEvent.clientX-t.touchStartX),t._handleSwipe(),"hover"===t._config.pause&&(t.pause(),t.touchTimeout&&clearTimeout(t.touchTimeout),t.touchTimeout=setTimeout((function(e){return t.cycle(e)}),500+t._config.interval))};i.default(this._element.querySelectorAll(".carousel-item img")).on("dragstart.bs.carousel",(function(t){return t.preventDefault()})),this._pointerEvent?(i.default(this._element).on("pointerdown.bs.carousel",(function(t){return e(t)})),i.default(this._element).on("pointerup.bs.carousel",(function(t){return n(t)})),this._element.classList.add("pointer-event")):(i.default(this._element).on("touchstart.bs.carousel",(function(t){return e(t)})),i.default(this._element).on("touchmove.bs.carousel",(function(e){return function(e){e.originalEvent.touches&&e.originalEvent.touches.length>1?t.touchDeltaX=0:t.touchDeltaX=e.originalEvent.touches[0].clientX-t.touchStartX}(e)})),i.default(this._element).on("touchend.bs.carousel",(function(t){return n(t)})))}},e._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next()}},e._getItemIndex=function(t){return this._items=t&&t.parentNode?[].slice.call(t.parentNode.querySelectorAll(".carousel-item")):[],this._items.indexOf(t)},e._getItemByDirection=function(t,e){var n="next"===t,i="prev"===t,o=this._getItemIndex(e),r=this._items.length-1;if((i&&0===o||n&&o===r)&&!this._config.wrap)return e;var a=(o+("prev"===t?-1:1))%this._items.length;return-1===a?this._items[this._items.length-1]:this._items[a]},e._triggerSlideEvent=function(t,e){var n=this._getItemIndex(t),o=this._getItemIndex(this._element.querySelector(".active.carousel-item")),r=i.default.Event("slide.bs.carousel",{relatedTarget:t,direction:e,from:o,to:n});return i.default(this._element).trigger(r),r},e._setActiveIndicatorElement=function(t){if(this._indicatorsElement){var e=[].slice.call(this._indicatorsElement.querySelectorAll(".active"));i.default(e).removeClass("active");var n=this._indicatorsElement.children[this._getItemIndex(t)];n&&i.default(n).addClass("active")}},e._slide=function(t,e){var n,o,r,a=this,s=this._element.querySelector(".active.carousel-item"),u=this._getItemIndex(s),f=e||s&&this._getItemByDirection(t,s),d=this._getItemIndex(f),c=Boolean(this._interval);if("next"===t?(n="carousel-item-left",o="carousel-item-next",r="left"):(n="carousel-item-right",o="carousel-item-prev",r="right"),f&&i.default(f).hasClass("active"))this._isSliding=!1;else if(!this._triggerSlideEvent(f,r).isDefaultPrevented()&&s&&f){this._isSliding=!0,c&&this.pause(),this._setActiveIndicatorElement(f);var h=i.default.Event("slid.bs.carousel",{relatedTarget:f,direction:r,from:u,to:d});if(i.default(this._element).hasClass("slide")){i.default(f).addClass(o),l.reflow(f),i.default(s).addClass(n),i.default(f).addClass(n);var p=parseInt(f.getAttribute("data-interval"),10);p?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=p):this._config.interval=this._config.defaultInterval||this._config.interval;var m=l.getTransitionDurationFromElement(s);i.default(s).one(l.TRANSITION_END,(function(){i.default(f).removeClass(n+" "+o).addClass("active"),i.default(s).removeClass("active "+o+" "+n),a._isSliding=!1,setTimeout((function(){return i.default(a._element).trigger(h)}),0)})).emulateTransitionEnd(m)}else i.default(s).removeClass("active"),i.default(f).addClass("active"),this._isSliding=!1,i.default(this._element).trigger(h);c&&this.cycle()}},t._jQueryInterface=function(e){return this.each((function(){var n=i.default(this).data("bs.carousel"),o=a({},v,i.default(this).data());"object"==typeof e&&(o=a({},o,e));var r="string"==typeof e?e:o.slide;if(n||(n=new t(this,o),i.default(this).data("bs.carousel",n)),"number"==typeof e)n.to(e);else if("string"==typeof r){if("undefined"==typeof n[r])throw new TypeError('No method named "'+r+'"');n[r]()}else o.interval&&o.ride&&(n.pause(),n.cycle())}))},t._dataApiClickHandler=function(e){var n=l.getSelectorFromElement(this);if(n){var o=i.default(n)[0];if(o&&i.default(o).hasClass("carousel")){var r=a({},i.default(o).data(),i.default(this).data()),s=this.getAttribute("data-slide-to");s&&(r.interval=!1),t._jQueryInterface.call(i.default(o),r),s&&i.default(o).data("bs.carousel").to(s),e.preventDefault()}}},r(t,null,[{key:"VERSION",get:function(){return"4.5.3"}},{key:"Default",get:function(){return v}}]),t}();i.default(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",y._dataApiClickHandler),i.default(window).on("load.bs.carousel.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-ride="carousel"]')),e=0,n=t.length;e0&&(this._selector=a,this._triggerArray.push(r))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}var e=t.prototype;return e.toggle=function(){i.default(this._element).hasClass("show")?this.hide():this.show()},e.show=function(){var e,n,o=this;if(!this._isTransitioning&&!i.default(this._element).hasClass("show")&&(this._parent&&0===(e=[].slice.call(this._parent.querySelectorAll(".show, .collapsing")).filter((function(t){return"string"==typeof o._config.parent?t.getAttribute("data-parent")===o._config.parent:t.classList.contains("collapse")}))).length&&(e=null),!(e&&(n=i.default(e).not(this._selector).data("bs.collapse"))&&n._isTransitioning))){var r=i.default.Event("show.bs.collapse");if(i.default(this._element).trigger(r),!r.isDefaultPrevented()){e&&(t._jQueryInterface.call(i.default(e).not(this._selector),"hide"),n||i.default(e).data("bs.collapse",null));var a=this._getDimension();i.default(this._element).removeClass("collapse").addClass("collapsing"),this._element.style[a]=0,this._triggerArray.length&&i.default(this._triggerArray).removeClass("collapsed").attr("aria-expanded",!0),this.setTransitioning(!0);var s="scroll"+(a[0].toUpperCase()+a.slice(1)),u=l.getTransitionDurationFromElement(this._element);i.default(this._element).one(l.TRANSITION_END,(function(){i.default(o._element).removeClass("collapsing").addClass("collapse show"),o._element.style[a]="",o.setTransitioning(!1),i.default(o._element).trigger("shown.bs.collapse")})).emulateTransitionEnd(u),this._element.style[a]=this._element[s]+"px"}}},e.hide=function(){var t=this;if(!this._isTransitioning&&i.default(this._element).hasClass("show")){var e=i.default.Event("hide.bs.collapse");if(i.default(this._element).trigger(e),!e.isDefaultPrevented()){var n=this._getDimension();this._element.style[n]=this._element.getBoundingClientRect()[n]+"px",l.reflow(this._element),i.default(this._element).addClass("collapsing").removeClass("collapse show");var o=this._triggerArray.length;if(o>0)for(var r=0;r=0)return 1;return 0}();var k=D&&window.Promise?function(t){var e=!1;return function(){e||(e=!0,window.Promise.resolve().then((function(){e=!1,t()})))}}:function(t){var e=!1;return function(){e||(e=!0,setTimeout((function(){e=!1,t()}),N))}};function A(t){return t&&"[object Function]"==={}.toString.call(t)}function I(t,e){if(1!==t.nodeType)return[];var n=t.ownerDocument.defaultView.getComputedStyle(t,null);return e?n[e]:n}function O(t){return"HTML"===t.nodeName?t:t.parentNode||t.host}function x(t){if(!t)return document.body;switch(t.nodeName){case"HTML":case"BODY":return t.ownerDocument.body;case"#document":return t.body}var e=I(t),n=e.overflow,i=e.overflowX,o=e.overflowY;return/(auto|scroll|overlay)/.test(n+o+i)?t:x(O(t))}function j(t){return t&&t.referenceNode?t.referenceNode:t}var L=D&&!(!window.MSInputMethodContext||!document.documentMode),P=D&&/MSIE 10/.test(navigator.userAgent);function F(t){return 11===t?L:10===t?P:L||P}function R(t){if(!t)return document.documentElement;for(var e=F(10)?document.body:null,n=t.offsetParent||null;n===e&&t.nextElementSibling;)n=(t=t.nextElementSibling).offsetParent;var i=n&&n.nodeName;return i&&"BODY"!==i&&"HTML"!==i?-1!==["TH","TD","TABLE"].indexOf(n.nodeName)&&"static"===I(n,"position")?R(n):n:t?t.ownerDocument.documentElement:document.documentElement}function H(t){return null!==t.parentNode?H(t.parentNode):t}function M(t,e){if(!(t&&t.nodeType&&e&&e.nodeType))return document.documentElement;var n=t.compareDocumentPosition(e)&Node.DOCUMENT_POSITION_FOLLOWING,i=n?t:e,o=n?e:t,r=document.createRange();r.setStart(i,0),r.setEnd(o,0);var a,s,l=r.commonAncestorContainer;if(t!==l&&e!==l||i.contains(o))return"BODY"===(s=(a=l).nodeName)||"HTML"!==s&&R(a.firstElementChild)!==a?R(l):l;var u=H(t);return u.host?M(u.host,e):M(t,H(e).host)}function B(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"top",n="top"===e?"scrollTop":"scrollLeft",i=t.nodeName;if("BODY"===i||"HTML"===i){var o=t.ownerDocument.documentElement,r=t.ownerDocument.scrollingElement||o;return r[n]}return t[n]}function q(t,e){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],i=B(e,"top"),o=B(e,"left"),r=n?-1:1;return t.top+=i*r,t.bottom+=i*r,t.left+=o*r,t.right+=o*r,t}function Q(t,e){var n="x"===e?"Left":"Top",i="Left"===n?"Right":"Bottom";return parseFloat(t["border"+n+"Width"])+parseFloat(t["border"+i+"Width"])}function W(t,e,n,i){return Math.max(e["offset"+t],e["scroll"+t],n["client"+t],n["offset"+t],n["scroll"+t],F(10)?parseInt(n["offset"+t])+parseInt(i["margin"+("Height"===t?"Top":"Left")])+parseInt(i["margin"+("Height"===t?"Bottom":"Right")]):0)}function U(t){var e=t.body,n=t.documentElement,i=F(10)&&getComputedStyle(n);return{height:W("Height",e,n,i),width:W("Width",e,n,i)}}var V=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},Y=function(){function t(t,e){for(var n=0;n2&&void 0!==arguments[2]&&arguments[2],i=F(10),o="HTML"===e.nodeName,r=G(t),a=G(e),s=x(t),l=I(e),u=parseFloat(l.borderTopWidth),f=parseFloat(l.borderLeftWidth);n&&o&&(a.top=Math.max(a.top,0),a.left=Math.max(a.left,0));var d=K({top:r.top-a.top-u,left:r.left-a.left-f,width:r.width,height:r.height});if(d.marginTop=0,d.marginLeft=0,!i&&o){var c=parseFloat(l.marginTop),h=parseFloat(l.marginLeft);d.top-=u-c,d.bottom-=u-c,d.left-=f-h,d.right-=f-h,d.marginTop=c,d.marginLeft=h}return(i&&!n?e.contains(s):e===s&&"BODY"!==s.nodeName)&&(d=q(d,e)),d}function J(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=t.ownerDocument.documentElement,i=$(t,n),o=Math.max(n.clientWidth,window.innerWidth||0),r=Math.max(n.clientHeight,window.innerHeight||0),a=e?0:B(n),s=e?0:B(n,"left"),l={top:a-i.top+i.marginTop,left:s-i.left+i.marginLeft,width:o,height:r};return K(l)}function Z(t){var e=t.nodeName;if("BODY"===e||"HTML"===e)return!1;if("fixed"===I(t,"position"))return!0;var n=O(t);return!!n&&Z(n)}function tt(t){if(!t||!t.parentElement||F())return document.documentElement;for(var e=t.parentElement;e&&"none"===I(e,"transform");)e=e.parentElement;return e||document.documentElement}function et(t,e,n,i){var o=arguments.length>4&&void 0!==arguments[4]&&arguments[4],r={top:0,left:0},a=o?tt(t):M(t,j(e));if("viewport"===i)r=J(a,o);else{var s=void 0;"scrollParent"===i?"BODY"===(s=x(O(e))).nodeName&&(s=t.ownerDocument.documentElement):s="window"===i?t.ownerDocument.documentElement:i;var l=$(s,a,o);if("HTML"!==s.nodeName||Z(a))r=l;else{var u=U(t.ownerDocument),f=u.height,d=u.width;r.top+=l.top-l.marginTop,r.bottom=f+l.top,r.left+=l.left-l.marginLeft,r.right=d+l.left}}var c="number"==typeof(n=n||0);return r.left+=c?n:n.left||0,r.top+=c?n:n.top||0,r.right-=c?n:n.right||0,r.bottom-=c?n:n.bottom||0,r}function nt(t){return t.width*t.height}function it(t,e,n,i,o){var r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0;if(-1===t.indexOf("auto"))return t;var a=et(n,i,r,o),s={top:{width:a.width,height:e.top-a.top},right:{width:a.right-e.right,height:a.height},bottom:{width:a.width,height:a.bottom-e.bottom},left:{width:e.left-a.left,height:a.height}},l=Object.keys(s).map((function(t){return X({key:t},s[t],{area:nt(s[t])})})).sort((function(t,e){return e.area-t.area})),u=l.filter((function(t){var e=t.width,i=t.height;return e>=n.clientWidth&&i>=n.clientHeight})),f=u.length>0?u[0].key:l[0].key,d=t.split("-")[1];return f+(d?"-"+d:"")}function ot(t,e,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null,o=i?tt(e):M(e,j(n));return $(n,o,i)}function rt(t){var e=t.ownerDocument.defaultView.getComputedStyle(t),n=parseFloat(e.marginTop||0)+parseFloat(e.marginBottom||0),i=parseFloat(e.marginLeft||0)+parseFloat(e.marginRight||0);return{width:t.offsetWidth+i,height:t.offsetHeight+n}}function at(t){var e={left:"right",right:"left",bottom:"top",top:"bottom"};return t.replace(/left|right|bottom|top/g,(function(t){return e[t]}))}function st(t,e,n){n=n.split("-")[0];var i=rt(t),o={width:i.width,height:i.height},r=-1!==["right","left"].indexOf(n),a=r?"top":"left",s=r?"left":"top",l=r?"height":"width",u=r?"width":"height";return o[a]=e[a]+e[l]/2-i[l]/2,o[s]=n===s?e[s]-i[u]:e[at(s)],o}function lt(t,e){return Array.prototype.find?t.find(e):t.filter(e)[0]}function ut(t,e,n){return(void 0===n?t:t.slice(0,function(t,e,n){if(Array.prototype.findIndex)return t.findIndex((function(t){return t[e]===n}));var i=lt(t,(function(t){return t[e]===n}));return t.indexOf(i)}(t,"name",n))).forEach((function(t){t.function&&console.warn("`modifier.function` is deprecated, use `modifier.fn`!");var n=t.function||t.fn;t.enabled&&A(n)&&(e.offsets.popper=K(e.offsets.popper),e.offsets.reference=K(e.offsets.reference),e=n(e,t))})),e}function ft(){if(!this.state.isDestroyed){var t={instance:this,styles:{},arrowStyles:{},attributes:{},flipped:!1,offsets:{}};t.offsets.reference=ot(this.state,this.popper,this.reference,this.options.positionFixed),t.placement=it(this.options.placement,t.offsets.reference,this.popper,this.reference,this.options.modifiers.flip.boundariesElement,this.options.modifiers.flip.padding),t.originalPlacement=t.placement,t.positionFixed=this.options.positionFixed,t.offsets.popper=st(this.popper,t.offsets.reference,t.placement),t.offsets.popper.position=this.options.positionFixed?"fixed":"absolute",t=ut(this.modifiers,t),this.state.isCreated?this.options.onUpdate(t):(this.state.isCreated=!0,this.options.onCreate(t))}}function dt(t,e){return t.some((function(t){var n=t.name;return t.enabled&&n===e}))}function ct(t){for(var e=[!1,"ms","Webkit","Moz","O"],n=t.charAt(0).toUpperCase()+t.slice(1),i=0;i1&&void 0!==arguments[1]&&arguments[1],n=Tt.indexOf(t),i=Tt.slice(n+1).concat(Tt.slice(0,n));return e?i.reverse():i}var St="flip",Dt="clockwise",Nt="counterclockwise";function kt(t,e,n,i){var o=[0,0],r=-1!==["right","left"].indexOf(i),a=t.split(/(\+|\-)/).map((function(t){return t.trim()})),s=a.indexOf(lt(a,(function(t){return-1!==t.search(/,|\s/)})));a[s]&&-1===a[s].indexOf(",")&&console.warn("Offsets separated by white space(s) are deprecated, use a comma (,) instead.");var l=/\s*,\s*|\s+/,u=-1!==s?[a.slice(0,s).concat([a[s].split(l)[0]]),[a[s].split(l)[1]].concat(a.slice(s+1))]:[a];return(u=u.map((function(t,i){var o=(1===i?!r:r)?"height":"width",a=!1;return t.reduce((function(t,e){return""===t[t.length-1]&&-1!==["+","-"].indexOf(e)?(t[t.length-1]=e,a=!0,t):a?(t[t.length-1]+=e,a=!1,t):t.concat(e)}),[]).map((function(t){return function(t,e,n,i){var o=t.match(/((?:\-|\+)?\d*\.?\d*)(.*)/),r=+o[1],a=o[2];if(!r)return t;if(0===a.indexOf("%")){var s=void 0;switch(a){case"%p":s=n;break;case"%":case"%r":default:s=i}return K(s)[e]/100*r}if("vh"===a||"vw"===a){return("vh"===a?Math.max(document.documentElement.clientHeight,window.innerHeight||0):Math.max(document.documentElement.clientWidth,window.innerWidth||0))/100*r}return r}(t,o,e,n)}))}))).forEach((function(t,e){t.forEach((function(n,i){_t(n)&&(o[e]+=n*("-"===t[i-1]?-1:1))}))})),o}var At={placement:"bottom",positionFixed:!1,eventsEnabled:!0,removeOnDestroy:!1,onCreate:function(){},onUpdate:function(){},modifiers:{shift:{order:100,enabled:!0,fn:function(t){var e=t.placement,n=e.split("-")[0],i=e.split("-")[1];if(i){var o=t.offsets,r=o.reference,a=o.popper,s=-1!==["bottom","top"].indexOf(n),l=s?"left":"top",u=s?"width":"height",f={start:z({},l,r[l]),end:z({},l,r[l]+r[u]-a[u])};t.offsets.popper=X({},a,f[i])}return t}},offset:{order:200,enabled:!0,fn:function(t,e){var n=e.offset,i=t.placement,o=t.offsets,r=o.popper,a=o.reference,s=i.split("-")[0],l=void 0;return l=_t(+n)?[+n,0]:kt(n,r,a,s),"left"===s?(r.top+=l[0],r.left-=l[1]):"right"===s?(r.top+=l[0],r.left+=l[1]):"top"===s?(r.left+=l[0],r.top-=l[1]):"bottom"===s&&(r.left+=l[0],r.top+=l[1]),t.popper=r,t},offset:0},preventOverflow:{order:300,enabled:!0,fn:function(t,e){var n=e.boundariesElement||R(t.instance.popper);t.instance.reference===n&&(n=R(n));var i=ct("transform"),o=t.instance.popper.style,r=o.top,a=o.left,s=o[i];o.top="",o.left="",o[i]="";var l=et(t.instance.popper,t.instance.reference,e.padding,n,t.positionFixed);o.top=r,o.left=a,o[i]=s,e.boundaries=l;var u=e.priority,f=t.offsets.popper,d={primary:function(t){var n=f[t];return f[t]l[t]&&!e.escapeWithReference&&(i=Math.min(f[n],l[t]-("right"===t?f.width:f.height))),z({},n,i)}};return u.forEach((function(t){var e=-1!==["left","top"].indexOf(t)?"primary":"secondary";f=X({},f,d[e](t))})),t.offsets.popper=f,t},priority:["left","right","top","bottom"],padding:5,boundariesElement:"scrollParent"},keepTogether:{order:400,enabled:!0,fn:function(t){var e=t.offsets,n=e.popper,i=e.reference,o=t.placement.split("-")[0],r=Math.floor,a=-1!==["top","bottom"].indexOf(o),s=a?"right":"bottom",l=a?"left":"top",u=a?"width":"height";return n[s]r(i[s])&&(t.offsets.popper[l]=r(i[s])),t}},arrow:{order:500,enabled:!0,fn:function(t,e){var n;if(!wt(t.instance.modifiers,"arrow","keepTogether"))return t;var i=e.element;if("string"==typeof i){if(!(i=t.instance.popper.querySelector(i)))return t}else if(!t.instance.popper.contains(i))return console.warn("WARNING: `arrow.element` must be child of its popper element!"),t;var o=t.placement.split("-")[0],r=t.offsets,a=r.popper,s=r.reference,l=-1!==["left","right"].indexOf(o),u=l?"height":"width",f=l?"Top":"Left",d=f.toLowerCase(),c=l?"left":"top",h=l?"bottom":"right",p=rt(i)[u];s[h]-pa[h]&&(t.offsets.popper[d]+=s[d]+p-a[h]),t.offsets.popper=K(t.offsets.popper);var m=s[d]+s[u]/2-p/2,g=I(t.instance.popper),v=parseFloat(g["margin"+f]),_=parseFloat(g["border"+f+"Width"]),b=m-t.offsets.popper[d]-v-_;return b=Math.max(Math.min(a[u]-p,b),0),t.arrowElement=i,t.offsets.arrow=(z(n={},d,Math.round(b)),z(n,c,""),n),t},element:"[x-arrow]"},flip:{order:600,enabled:!0,fn:function(t,e){if(dt(t.instance.modifiers,"inner"))return t;if(t.flipped&&t.placement===t.originalPlacement)return t;var n=et(t.instance.popper,t.instance.reference,e.padding,e.boundariesElement,t.positionFixed),i=t.placement.split("-")[0],o=at(i),r=t.placement.split("-")[1]||"",a=[];switch(e.behavior){case St:a=[i,o];break;case Dt:a=Ct(i);break;case Nt:a=Ct(i,!0);break;default:a=e.behavior}return a.forEach((function(s,l){if(i!==s||a.length===l+1)return t;i=t.placement.split("-")[0],o=at(i);var u=t.offsets.popper,f=t.offsets.reference,d=Math.floor,c="left"===i&&d(u.right)>d(f.left)||"right"===i&&d(u.left)d(f.top)||"bottom"===i&&d(u.top)d(n.right),m=d(u.top)d(n.bottom),v="left"===i&&h||"right"===i&&p||"top"===i&&m||"bottom"===i&&g,_=-1!==["top","bottom"].indexOf(i),b=!!e.flipVariations&&(_&&"start"===r&&h||_&&"end"===r&&p||!_&&"start"===r&&m||!_&&"end"===r&&g),y=!!e.flipVariationsByContent&&(_&&"start"===r&&p||_&&"end"===r&&h||!_&&"start"===r&&g||!_&&"end"===r&&m),w=b||y;(c||v||w)&&(t.flipped=!0,(c||v)&&(i=a[l+1]),w&&(r=function(t){return"end"===t?"start":"start"===t?"end":t}(r)),t.placement=i+(r?"-"+r:""),t.offsets.popper=X({},t.offsets.popper,st(t.instance.popper,t.offsets.reference,t.placement)),t=ut(t.instance.modifiers,t,"flip"))})),t},behavior:"flip",padding:5,boundariesElement:"viewport",flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:function(t){var e=t.placement,n=e.split("-")[0],i=t.offsets,o=i.popper,r=i.reference,a=-1!==["left","right"].indexOf(n),s=-1===["top","left"].indexOf(n);return o[a?"left":"top"]=r[n]-(s?o[a?"width":"height"]:0),t.placement=at(e),t.offsets.popper=K(o),t}},hide:{order:800,enabled:!0,fn:function(t){if(!wt(t.instance.modifiers,"hide","preventOverflow"))return t;var e=t.offsets.reference,n=lt(t.instance.modifiers,(function(t){return"preventOverflow"===t.name})).boundaries;if(e.bottomn.right||e.top>n.bottom||e.right2&&void 0!==arguments[2]?arguments[2]:{};V(this,t),this.scheduleUpdate=function(){return requestAnimationFrame(i.update)},this.update=k(this.update.bind(this)),this.options=X({},t.Defaults,o),this.state={isDestroyed:!1,isCreated:!1,scrollParents:[]},this.reference=e&&e.jquery?e[0]:e,this.popper=n&&n.jquery?n[0]:n,this.options.modifiers={},Object.keys(X({},t.Defaults.modifiers,o.modifiers)).forEach((function(e){i.options.modifiers[e]=X({},t.Defaults.modifiers[e]||{},o.modifiers?o.modifiers[e]:{})})),this.modifiers=Object.keys(this.options.modifiers).map((function(t){return X({name:t},i.options.modifiers[t])})).sort((function(t,e){return t.order-e.order})),this.modifiers.forEach((function(t){t.enabled&&A(t.onLoad)&&t.onLoad(i.reference,i.popper,i.options,t,i.state)})),this.update();var r=this.options.eventsEnabled;r&&this.enableEventListeners(),this.state.eventsEnabled=r}return Y(t,[{key:"update",value:function(){return ft.call(this)}},{key:"destroy",value:function(){return ht.call(this)}},{key:"enableEventListeners",value:function(){return gt.call(this)}},{key:"disableEventListeners",value:function(){return vt.call(this)}}]),t}();It.Utils=("undefined"!=typeof window?window:global).PopperUtils,It.placements=Et,It.Defaults=At;var Ot="dropdown",xt=i.default.fn[Ot],jt=new RegExp("38|40|27"),Lt={offset:0,flip:!0,boundary:"scrollParent",reference:"toggle",display:"dynamic",popperConfig:null},Pt={offset:"(number|string|function)",flip:"boolean",boundary:"(string|element)",reference:"(string|element)",display:"string",popperConfig:"(null|object)"},Ft=function(){function t(t,e){this._element=t,this._popper=null,this._config=this._getConfig(e),this._menu=this._getMenuElement(),this._inNavbar=this._detectNavbar(),this._addEventListeners()}var e=t.prototype;return e.toggle=function(){if(!this._element.disabled&&!i.default(this._element).hasClass("disabled")){var e=i.default(this._menu).hasClass("show");t._clearMenus(),e||this.show(!0)}},e.show=function(e){if(void 0===e&&(e=!1),!(this._element.disabled||i.default(this._element).hasClass("disabled")||i.default(this._menu).hasClass("show"))){var n={relatedTarget:this._element},o=i.default.Event("show.bs.dropdown",n),r=t._getParentFromElement(this._element);if(i.default(r).trigger(o),!o.isDefaultPrevented()){if(!this._inNavbar&&e){if("undefined"==typeof It)throw new TypeError("Bootstrap's dropdowns require Popper.js (https://popper.js.org/)");var a=this._element;"parent"===this._config.reference?a=r:l.isElement(this._config.reference)&&(a=this._config.reference,"undefined"!=typeof this._config.reference.jquery&&(a=this._config.reference[0])),"scrollParent"!==this._config.boundary&&i.default(r).addClass("position-static"),this._popper=new It(a,this._menu,this._getPopperConfig())}"ontouchstart"in document.documentElement&&0===i.default(r).closest(".navbar-nav").length&&i.default(document.body).children().on("mouseover",null,i.default.noop),this._element.focus(),this._element.setAttribute("aria-expanded",!0),i.default(this._menu).toggleClass("show"),i.default(r).toggleClass("show").trigger(i.default.Event("shown.bs.dropdown",n))}}},e.hide=function(){if(!this._element.disabled&&!i.default(this._element).hasClass("disabled")&&i.default(this._menu).hasClass("show")){var e={relatedTarget:this._element},n=i.default.Event("hide.bs.dropdown",e),o=t._getParentFromElement(this._element);i.default(o).trigger(n),n.isDefaultPrevented()||(this._popper&&this._popper.destroy(),i.default(this._menu).toggleClass("show"),i.default(o).toggleClass("show").trigger(i.default.Event("hidden.bs.dropdown",e)))}},e.dispose=function(){i.default.removeData(this._element,"bs.dropdown"),i.default(this._element).off(".bs.dropdown"),this._element=null,this._menu=null,null!==this._popper&&(this._popper.destroy(),this._popper=null)},e.update=function(){this._inNavbar=this._detectNavbar(),null!==this._popper&&this._popper.scheduleUpdate()},e._addEventListeners=function(){var t=this;i.default(this._element).on("click.bs.dropdown",(function(e){e.preventDefault(),e.stopPropagation(),t.toggle()}))},e._getConfig=function(t){return t=a({},this.constructor.Default,i.default(this._element).data(),t),l.typeCheckConfig(Ot,t,this.constructor.DefaultType),t},e._getMenuElement=function(){if(!this._menu){var e=t._getParentFromElement(this._element);e&&(this._menu=e.querySelector(".dropdown-menu"))}return this._menu},e._getPlacement=function(){var t=i.default(this._element.parentNode),e="bottom-start";return t.hasClass("dropup")?e=i.default(this._menu).hasClass("dropdown-menu-right")?"top-end":"top-start":t.hasClass("dropright")?e="right-start":t.hasClass("dropleft")?e="left-start":i.default(this._menu).hasClass("dropdown-menu-right")&&(e="bottom-end"),e},e._detectNavbar=function(){return i.default(this._element).closest(".navbar").length>0},e._getOffset=function(){var t=this,e={};return"function"==typeof this._config.offset?e.fn=function(e){return e.offsets=a({},e.offsets,t._config.offset(e.offsets,t._element)||{}),e}:e.offset=this._config.offset,e},e._getPopperConfig=function(){var t={placement:this._getPlacement(),modifiers:{offset:this._getOffset(),flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}};return"static"===this._config.display&&(t.modifiers.applyStyle={enabled:!1}),a({},t,this._config.popperConfig)},t._jQueryInterface=function(e){return this.each((function(){var n=i.default(this).data("bs.dropdown");if(n||(n=new t(this,"object"==typeof e?e:null),i.default(this).data("bs.dropdown",n)),"string"==typeof e){if("undefined"==typeof n[e])throw new TypeError('No method named "'+e+'"');n[e]()}}))},t._clearMenus=function(e){if(!e||3!==e.which&&("keyup"!==e.type||9===e.which))for(var n=[].slice.call(document.querySelectorAll('[data-toggle="dropdown"]')),o=0,r=n.length;o0&&a--,40===e.which&&adocument.documentElement.clientHeight;n||(this._element.style.overflowY="hidden"),this._element.classList.add("modal-static");var o=l.getTransitionDurationFromElement(this._dialog);i.default(this._element).off(l.TRANSITION_END),i.default(this._element).one(l.TRANSITION_END,(function(){t._element.classList.remove("modal-static"),n||i.default(t._element).one(l.TRANSITION_END,(function(){t._element.style.overflowY=""})).emulateTransitionEnd(t._element,o)})).emulateTransitionEnd(o),this._element.focus()}else this.hide()},e._showElement=function(t){var e=this,n=i.default(this._element).hasClass("fade"),o=this._dialog?this._dialog.querySelector(".modal-body"):null;this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),i.default(this._dialog).hasClass("modal-dialog-scrollable")&&o?o.scrollTop=0:this._element.scrollTop=0,n&&l.reflow(this._element),i.default(this._element).addClass("show"),this._config.focus&&this._enforceFocus();var r=i.default.Event("shown.bs.modal",{relatedTarget:t}),a=function(){e._config.focus&&e._element.focus(),e._isTransitioning=!1,i.default(e._element).trigger(r)};if(n){var s=l.getTransitionDurationFromElement(this._dialog);i.default(this._dialog).one(l.TRANSITION_END,a).emulateTransitionEnd(s)}else a()},e._enforceFocus=function(){var t=this;i.default(document).off("focusin.bs.modal").on("focusin.bs.modal",(function(e){document!==e.target&&t._element!==e.target&&0===i.default(t._element).has(e.target).length&&t._element.focus()}))},e._setEscapeEvent=function(){var t=this;this._isShown?i.default(this._element).on("keydown.dismiss.bs.modal",(function(e){t._config.keyboard&&27===e.which?(e.preventDefault(),t.hide()):t._config.keyboard||27!==e.which||t._triggerBackdropTransition()})):this._isShown||i.default(this._element).off("keydown.dismiss.bs.modal")},e._setResizeEvent=function(){var t=this;this._isShown?i.default(window).on("resize.bs.modal",(function(e){return t.handleUpdate(e)})):i.default(window).off("resize.bs.modal")},e._hideModal=function(){var t=this;this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._showBackdrop((function(){i.default(document.body).removeClass("modal-open"),t._resetAdjustments(),t._resetScrollbar(),i.default(t._element).trigger("hidden.bs.modal")}))},e._removeBackdrop=function(){this._backdrop&&(i.default(this._backdrop).remove(),this._backdrop=null)},e._showBackdrop=function(t){var e=this,n=i.default(this._element).hasClass("fade")?"fade":"";if(this._isShown&&this._config.backdrop){if(this._backdrop=document.createElement("div"),this._backdrop.className="modal-backdrop",n&&this._backdrop.classList.add(n),i.default(this._backdrop).appendTo(document.body),i.default(this._element).on("click.dismiss.bs.modal",(function(t){e._ignoreBackdropClick?e._ignoreBackdropClick=!1:t.target===t.currentTarget&&e._triggerBackdropTransition()})),n&&l.reflow(this._backdrop),i.default(this._backdrop).addClass("show"),!t)return;if(!n)return void t();var o=l.getTransitionDurationFromElement(this._backdrop);i.default(this._backdrop).one(l.TRANSITION_END,t).emulateTransitionEnd(o)}else if(!this._isShown&&this._backdrop){i.default(this._backdrop).removeClass("show");var r=function(){e._removeBackdrop(),t&&t()};if(i.default(this._element).hasClass("fade")){var a=l.getTransitionDurationFromElement(this._backdrop);i.default(this._backdrop).one(l.TRANSITION_END,r).emulateTransitionEnd(a)}else r()}else t&&t()},e._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},e._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},e._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=Math.round(t.left+t.right)
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",sanitize:!0,sanitizeFn:null,whiteList:Qt,popperConfig:null},Zt={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},te=function(){function t(t,e){if("undefined"==typeof It)throw new TypeError("Bootstrap's tooltips require Popper.js (https://popper.js.org/)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var e=t.prototype;return e.enable=function(){this._isEnabled=!0},e.disable=function(){this._isEnabled=!1},e.toggleEnabled=function(){this._isEnabled=!this._isEnabled},e.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=i.default(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),i.default(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(i.default(this.getTipElement()).hasClass("show"))return void this._leave(null,this);this._enter(null,this)}},e.dispose=function(){clearTimeout(this._timeout),i.default.removeData(this.element,this.constructor.DATA_KEY),i.default(this.element).off(this.constructor.EVENT_KEY),i.default(this.element).closest(".modal").off("hide.bs.modal",this._hideModalHandler),this.tip&&i.default(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},e.show=function(){var t=this;if("none"===i.default(this.element).css("display"))throw new Error("Please use show on visible elements");var e=i.default.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){i.default(this.element).trigger(e);var n=l.findShadowRoot(this.element),o=i.default.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(e.isDefaultPrevented()||!o)return;var r=this.getTipElement(),a=l.getUID(this.constructor.NAME);r.setAttribute("id",a),this.element.setAttribute("aria-describedby",a),this.setContent(),this.config.animation&&i.default(r).addClass("fade");var s="function"==typeof this.config.placement?this.config.placement.call(this,r,this.element):this.config.placement,u=this._getAttachment(s);this.addAttachmentClass(u);var f=this._getContainer();i.default(r).data(this.constructor.DATA_KEY,this),i.default.contains(this.element.ownerDocument.documentElement,this.tip)||i.default(r).appendTo(f),i.default(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new It(this.element,r,this._getPopperConfig(u)),i.default(r).addClass("show"),"ontouchstart"in document.documentElement&&i.default(document.body).children().on("mouseover",null,i.default.noop);var d=function(){t.config.animation&&t._fixTransition();var e=t._hoverState;t._hoverState=null,i.default(t.element).trigger(t.constructor.Event.SHOWN),"out"===e&&t._leave(null,t)};if(i.default(this.tip).hasClass("fade")){var c=l.getTransitionDurationFromElement(this.tip);i.default(this.tip).one(l.TRANSITION_END,d).emulateTransitionEnd(c)}else d()}},e.hide=function(t){var e=this,n=this.getTipElement(),o=i.default.Event(this.constructor.Event.HIDE),r=function(){"show"!==e._hoverState&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),i.default(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(i.default(this.element).trigger(o),!o.isDefaultPrevented()){if(i.default(n).removeClass("show"),"ontouchstart"in document.documentElement&&i.default(document.body).children().off("mouseover",null,i.default.noop),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,i.default(this.tip).hasClass("fade")){var a=l.getTransitionDurationFromElement(n);i.default(n).one(l.TRANSITION_END,r).emulateTransitionEnd(a)}else r();this._hoverState=""}},e.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},e.isWithContent=function(){return Boolean(this.getTitle())},e.addAttachmentClass=function(t){i.default(this.getTipElement()).addClass("bs-tooltip-"+t)},e.getTipElement=function(){return this.tip=this.tip||i.default(this.config.template)[0],this.tip},e.setContent=function(){var t=this.getTipElement();this.setElementContent(i.default(t.querySelectorAll(".tooltip-inner")),this.getTitle()),i.default(t).removeClass("fade show")},e.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=Vt(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?i.default(e).parent().is(t)||t.empty().append(e):t.text(i.default(e).text())},e.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},e._getPopperConfig=function(t){var e=this;return a({},{placement:t,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:".arrow"},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}},this.config.popperConfig)},e._getOffset=function(){var t=this,e={};return"function"==typeof this.config.offset?e.fn=function(e){return e.offsets=a({},e.offsets,t.config.offset(e.offsets,t.element)||{}),e}:e.offset=this.config.offset,e},e._getContainer=function(){return!1===this.config.container?document.body:l.isElement(this.config.container)?i.default(this.config.container):i.default(document).find(this.config.container)},e._getAttachment=function(t){return $t[t.toUpperCase()]},e._setListeners=function(){var t=this;this.config.trigger.split(" ").forEach((function(e){if("click"===e)i.default(t.element).on(t.constructor.Event.CLICK,t.config.selector,(function(e){return t.toggle(e)}));else if("manual"!==e){var n="hover"===e?t.constructor.Event.MOUSEENTER:t.constructor.Event.FOCUSIN,o="hover"===e?t.constructor.Event.MOUSELEAVE:t.constructor.Event.FOCUSOUT;i.default(t.element).on(n,t.config.selector,(function(e){return t._enter(e)})).on(o,t.config.selector,(function(e){return t._leave(e)}))}})),this._hideModalHandler=function(){t.element&&t.hide()},i.default(this.element).closest(".modal").on("hide.bs.modal",this._hideModalHandler),this.config.selector?this.config=a({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},e._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},e._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||i.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),i.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?"focus":"hover"]=!0),i.default(e.getTipElement()).hasClass("show")||"show"===e._hoverState?e._hoverState="show":(clearTimeout(e._timeout),e._hoverState="show",e.config.delay&&e.config.delay.show?e._timeout=setTimeout((function(){"show"===e._hoverState&&e.show()}),e.config.delay.show):e.show())},e._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||i.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),i.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?"focus":"hover"]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState="out",e.config.delay&&e.config.delay.hide?e._timeout=setTimeout((function(){"out"===e._hoverState&&e.hide()}),e.config.delay.hide):e.hide())},e._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},e._getConfig=function(t){var e=i.default(this.element).data();return Object.keys(e).forEach((function(t){-1!==Kt.indexOf(t)&&delete e[t]})),"number"==typeof(t=a({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),l.typeCheckConfig(Yt,t,this.constructor.DefaultType),t.sanitize&&(t.template=Vt(t.template,t.whiteList,t.sanitizeFn)),t},e._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},e._cleanTipClass=function(){var t=i.default(this.getTipElement()),e=t.attr("class").match(Xt);null!==e&&e.length&&t.removeClass(e.join(""))},e._handlePopperPlacementChange=function(t){this.tip=t.instance.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},e._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(i.default(t).removeClass("fade"),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},t._jQueryInterface=function(e){return this.each((function(){var n=i.default(this),o=n.data("bs.tooltip"),r="object"==typeof e&&e;if((o||!/dispose|hide/.test(e))&&(o||(o=new t(this,r),n.data("bs.tooltip",o)),"string"==typeof e)){if("undefined"==typeof o[e])throw new TypeError('No method named "'+e+'"');o[e]()}}))},r(t,null,[{key:"VERSION",get:function(){return"4.5.3"}},{key:"Default",get:function(){return Jt}},{key:"NAME",get:function(){return Yt}},{key:"DATA_KEY",get:function(){return"bs.tooltip"}},{key:"Event",get:function(){return Zt}},{key:"EVENT_KEY",get:function(){return".bs.tooltip"}},{key:"DefaultType",get:function(){return Gt}}]),t}();i.default.fn[Yt]=te._jQueryInterface,i.default.fn[Yt].Constructor=te,i.default.fn[Yt].noConflict=function(){return i.default.fn[Yt]=zt,te._jQueryInterface};var ee="popover",ne=i.default.fn[ee],ie=new RegExp("(^|\\s)bs-popover\\S+","g"),oe=a({},te.Default,{placement:"right",trigger:"click",content:"",template:''}),re=a({},te.DefaultType,{content:"(string|element|function)"}),ae={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"},se=function(t){var e,n;function o(){return t.apply(this,arguments)||this}n=t,(e=o).prototype=Object.create(n.prototype),e.prototype.constructor=e,e.__proto__=n;var a=o.prototype;return a.isWithContent=function(){return this.getTitle()||this._getContent()},a.addAttachmentClass=function(t){i.default(this.getTipElement()).addClass("bs-popover-"+t)},a.getTipElement=function(){return this.tip=this.tip||i.default(this.config.template)[0],this.tip},a.setContent=function(){var t=i.default(this.getTipElement());this.setElementContent(t.find(".popover-header"),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(".popover-body"),e),t.removeClass("fade show")},a._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},a._cleanTipClass=function(){var t=i.default(this.getTipElement()),e=t.attr("class").match(ie);null!==e&&e.length>0&&t.removeClass(e.join(""))},o._jQueryInterface=function(t){return this.each((function(){var e=i.default(this).data("bs.popover"),n="object"==typeof t?t:null;if((e||!/dispose|hide/.test(t))&&(e||(e=new o(this,n),i.default(this).data("bs.popover",e)),"string"==typeof t)){if("undefined"==typeof e[t])throw new TypeError('No method named "'+t+'"');e[t]()}}))},r(o,null,[{key:"VERSION",get:function(){return"4.5.3"}},{key:"Default",get:function(){return oe}},{key:"NAME",get:function(){return ee}},{key:"DATA_KEY",get:function(){return"bs.popover"}},{key:"Event",get:function(){return ae}},{key:"EVENT_KEY",get:function(){return".bs.popover"}},{key:"DefaultType",get:function(){return re}}]),o}(te);i.default.fn[ee]=se._jQueryInterface,i.default.fn[ee].Constructor=se,i.default.fn[ee].noConflict=function(){return i.default.fn[ee]=ne,se._jQueryInterface};var le="scrollspy",ue=i.default.fn[le],fe={offset:10,method:"auto",target:""},de={offset:"number",method:"string",target:"(string|element)"},ce=function(){function t(t,e){var n=this;this._element=t,this._scrollElement="BODY"===t.tagName?window:t,this._config=this._getConfig(e),this._selector=this._config.target+" .nav-link,"+this._config.target+" .list-group-item,"+this._config.target+" .dropdown-item",this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,i.default(this._scrollElement).on("scroll.bs.scrollspy",(function(t){return n._process(t)})),this.refresh(),this._process()}var e=t.prototype;return e.refresh=function(){var t=this,e=this._scrollElement===this._scrollElement.window?"offset":"position",n="auto"===this._config.method?e:this._config.method,o="position"===n?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),[].slice.call(document.querySelectorAll(this._selector)).map((function(t){var e,r=l.getSelectorFromElement(t);if(r&&(e=document.querySelector(r)),e){var a=e.getBoundingClientRect();if(a.width||a.height)return[i.default(e)[n]().top+o,r]}return null})).filter((function(t){return t})).sort((function(t,e){return t[0]-e[0]})).forEach((function(e){t._offsets.push(e[0]),t._targets.push(e[1])}))},e.dispose=function(){i.default.removeData(this._element,"bs.scrollspy"),i.default(this._scrollElement).off(".bs.scrollspy"),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},e._getConfig=function(t){if("string"!=typeof(t=a({},fe,"object"==typeof t&&t?t:{})).target&&l.isElement(t.target)){var e=i.default(t.target).attr("id");e||(e=l.getUID(le),i.default(t.target).attr("id",e)),t.target="#"+e}return l.typeCheckConfig(le,t,de),t},e._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},e._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},e._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},e._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;){this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||t li > .active":".active";n=(n=i.default.makeArray(i.default(o).find(a)))[n.length-1]}var s=i.default.Event("hide.bs.tab",{relatedTarget:this._element}),u=i.default.Event("show.bs.tab",{relatedTarget:n});if(n&&i.default(n).trigger(s),i.default(this._element).trigger(u),!u.isDefaultPrevented()&&!s.isDefaultPrevented()){r&&(e=document.querySelector(r)),this._activate(this._element,o);var f=function(){var e=i.default.Event("hidden.bs.tab",{relatedTarget:t._element}),o=i.default.Event("shown.bs.tab",{relatedTarget:n});i.default(n).trigger(e),i.default(t._element).trigger(o)};e?this._activate(e,e.parentNode,f):f()}}},e.dispose=function(){i.default.removeData(this._element,"bs.tab"),this._element=null},e._activate=function(t,e,n){var o=this,r=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?i.default(e).children(".active"):i.default(e).find("> li > .active"))[0],a=n&&r&&i.default(r).hasClass("fade"),s=function(){return o._transitionComplete(t,r,n)};if(r&&a){var u=l.getTransitionDurationFromElement(r);i.default(r).removeClass("show").one(l.TRANSITION_END,s).emulateTransitionEnd(u)}else s()},e._transitionComplete=function(t,e,n){if(e){i.default(e).removeClass("active");var o=i.default(e.parentNode).find("> .dropdown-menu .active")[0];o&&i.default(o).removeClass("active"),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}if(i.default(t).addClass("active"),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),l.reflow(t),t.classList.contains("fade")&&t.classList.add("show"),t.parentNode&&i.default(t.parentNode).hasClass("dropdown-menu")){var r=i.default(t).closest(".dropdown")[0];if(r){var a=[].slice.call(r.querySelectorAll(".dropdown-toggle"));i.default(a).addClass("active")}t.setAttribute("aria-expanded",!0)}n&&n()},t._jQueryInterface=function(e){return this.each((function(){var n=i.default(this),o=n.data("bs.tab");if(o||(o=new t(this),n.data("bs.tab",o)),"string"==typeof e){if("undefined"==typeof o[e])throw new TypeError('No method named "'+e+'"');o[e]()}}))},r(t,null,[{key:"VERSION",get:function(){return"4.5.3"}}]),t}();i.default(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',(function(t){t.preventDefault(),pe._jQueryInterface.call(i.default(this),"show")})),i.default.fn.tab=pe._jQueryInterface,i.default.fn.tab.Constructor=pe,i.default.fn.tab.noConflict=function(){return i.default.fn.tab=he,pe._jQueryInterface};var me=i.default.fn.toast,ge={animation:"boolean",autohide:"boolean",delay:"number"},ve={animation:!0,autohide:!0,delay:500},_e=function(){function t(t,e){this._element=t,this._config=this._getConfig(e),this._timeout=null,this._setListeners()}var e=t.prototype;return e.show=function(){var t=this,e=i.default.Event("show.bs.toast");if(i.default(this._element).trigger(e),!e.isDefaultPrevented()){this._clearTimeout(),this._config.animation&&this._element.classList.add("fade");var n=function(){t._element.classList.remove("showing"),t._element.classList.add("show"),i.default(t._element).trigger("shown.bs.toast"),t._config.autohide&&(t._timeout=setTimeout((function(){t.hide()}),t._config.delay))};if(this._element.classList.remove("hide"),l.reflow(this._element),this._element.classList.add("showing"),this._config.animation){var o=l.getTransitionDurationFromElement(this._element);i.default(this._element).one(l.TRANSITION_END,n).emulateTransitionEnd(o)}else n()}},e.hide=function(){if(this._element.classList.contains("show")){var t=i.default.Event("hide.bs.toast");i.default(this._element).trigger(t),t.isDefaultPrevented()||this._close()}},e.dispose=function(){this._clearTimeout(),this._element.classList.contains("show")&&this._element.classList.remove("show"),i.default(this._element).off("click.dismiss.bs.toast"),i.default.removeData(this._element,"bs.toast"),this._element=null,this._config=null},e._getConfig=function(t){return t=a({},ve,i.default(this._element).data(),"object"==typeof t&&t?t:{}),l.typeCheckConfig("toast",t,this.constructor.DefaultType),t},e._setListeners=function(){var t=this;i.default(this._element).on("click.dismiss.bs.toast",'[data-dismiss="toast"]',(function(){return t.hide()}))},e._close=function(){var t=this,e=function(){t._element.classList.add("hide"),i.default(t._element).trigger("hidden.bs.toast")};if(this._element.classList.remove("show"),this._config.animation){var n=l.getTransitionDurationFromElement(this._element);i.default(this._element).one(l.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},e._clearTimeout=function(){clearTimeout(this._timeout),this._timeout=null},t._jQueryInterface=function(e){return this.each((function(){var n=i.default(this),o=n.data("bs.toast");if(o||(o=new t(this,"object"==typeof e&&e),n.data("bs.toast",o)),"string"==typeof e){if("undefined"==typeof o[e])throw new TypeError('No method named "'+e+'"');o[e](this)}}))},r(t,null,[{key:"VERSION",get:function(){return"4.5.3"}},{key:"DefaultType",get:function(){return ge}},{key:"Default",get:function(){return ve}}]),t}();i.default.fn.toast=_e._jQueryInterface,i.default.fn.toast.Constructor=_e,i.default.fn.toast.noConflict=function(){return i.default.fn.toast=me,_e._jQueryInterface},t.Alert=d,t.Button=h,t.Carousel=y,t.Collapse=S,t.Dropdown=Ft,t.Modal=Bt,t.Popover=se,t.Scrollspy=ce,t.Tab=pe,t.Toast=_e,t.Tooltip=te,t.Util=l,Object.defineProperty(t,"__esModule",{value:!0})})); -//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/static/kevin-master/assets/css/animate.css b/static/kevin-master/assets/css/animate.css deleted file mode 100644 index 7148b57..0000000 --- a/static/kevin-master/assets/css/animate.css +++ /dev/null @@ -1,3340 +0,0 @@ -@charset "UTF-8"; - -/*! - * animate.css -http://daneden.me/animate - * Version - 3.5.1 - * Licensed under the MIT license - http://opensource.org/licenses/MIT - * - * Copyright (c) 2016 Daniel Eden - */ - -.animated { - -webkit-animation-duration: 1s; - animation-duration: 1s; - -webkit-animation-fill-mode: both; - animation-fill-mode: both; -} - -.animated.infinite { - -webkit-animation-iteration-count: infinite; - animation-iteration-count: infinite; -} - -.animated.hinge { - -webkit-animation-duration: 2s; - animation-duration: 2s; -} - -.animated.flipOutX, -.animated.flipOutY, -.animated.bounceIn, -.animated.bounceOut { - -webkit-animation-duration: .75s; - animation-duration: .75s; -} - -@-webkit-keyframes bounce { - from, 20%, 53%, 80%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - -webkit-transform: translate3d(0,0,0); - transform: translate3d(0,0,0); - } - - 40%, 43% { - -webkit-animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); - animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); - -webkit-transform: translate3d(0, -30px, 0); - transform: translate3d(0, -30px, 0); - } - - 70% { - -webkit-animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); - animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); - -webkit-transform: translate3d(0, -15px, 0); - transform: translate3d(0, -15px, 0); - } - - 90% { - -webkit-transform: translate3d(0,-4px,0); - transform: translate3d(0,-4px,0); - } -} - -@keyframes bounce { - from, 20%, 53%, 80%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - -webkit-transform: translate3d(0,0,0); - transform: translate3d(0,0,0); - } - - 40%, 43% { - -webkit-animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); - animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); - -webkit-transform: translate3d(0, -30px, 0); - transform: translate3d(0, -30px, 0); - } - - 70% { - -webkit-animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); - animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); - -webkit-transform: translate3d(0, -15px, 0); - transform: translate3d(0, -15px, 0); - } - - 90% { - -webkit-transform: translate3d(0,-4px,0); - transform: translate3d(0,-4px,0); - } -} - -.bounce { - -webkit-animation-name: bounce; - animation-name: bounce; - -webkit-transform-origin: center bottom; - transform-origin: center bottom; -} - -@-webkit-keyframes flash { - from, 50%, to { - opacity: 1; - } - - 25%, 75% { - opacity: 0; - } -} - -@keyframes flash { - from, 50%, to { - opacity: 1; - } - - 25%, 75% { - opacity: 0; - } -} - -.flash { - -webkit-animation-name: flash; - animation-name: flash; -} - -/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ - -@-webkit-keyframes pulse { - from { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } - - 50% { - -webkit-transform: scale3d(1.05, 1.05, 1.05); - transform: scale3d(1.05, 1.05, 1.05); - } - - to { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -@keyframes pulse { - from { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } - - 50% { - -webkit-transform: scale3d(1.05, 1.05, 1.05); - transform: scale3d(1.05, 1.05, 1.05); - } - - to { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -.pulse { - -webkit-animation-name: pulse; - animation-name: pulse; -} - -@-webkit-keyframes rubberBand { - from { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } - - 30% { - -webkit-transform: scale3d(1.25, 0.75, 1); - transform: scale3d(1.25, 0.75, 1); - } - - 40% { - -webkit-transform: scale3d(0.75, 1.25, 1); - transform: scale3d(0.75, 1.25, 1); - } - - 50% { - -webkit-transform: scale3d(1.15, 0.85, 1); - transform: scale3d(1.15, 0.85, 1); - } - - 65% { - -webkit-transform: scale3d(.95, 1.05, 1); - transform: scale3d(.95, 1.05, 1); - } - - 75% { - -webkit-transform: scale3d(1.05, .95, 1); - transform: scale3d(1.05, .95, 1); - } - - to { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -@keyframes rubberBand { - from { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } - - 30% { - -webkit-transform: scale3d(1.25, 0.75, 1); - transform: scale3d(1.25, 0.75, 1); - } - - 40% { - -webkit-transform: scale3d(0.75, 1.25, 1); - transform: scale3d(0.75, 1.25, 1); - } - - 50% { - -webkit-transform: scale3d(1.15, 0.85, 1); - transform: scale3d(1.15, 0.85, 1); - } - - 65% { - -webkit-transform: scale3d(.95, 1.05, 1); - transform: scale3d(.95, 1.05, 1); - } - - 75% { - -webkit-transform: scale3d(1.05, .95, 1); - transform: scale3d(1.05, .95, 1); - } - - to { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -.rubberBand { - -webkit-animation-name: rubberBand; - animation-name: rubberBand; -} - -@-webkit-keyframes shake { - from, to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - 10%, 30%, 50%, 70%, 90% { - -webkit-transform: translate3d(-10px, 0, 0); - transform: translate3d(-10px, 0, 0); - } - - 20%, 40%, 60%, 80% { - -webkit-transform: translate3d(10px, 0, 0); - transform: translate3d(10px, 0, 0); - } -} - -@keyframes shake { - from, to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - 10%, 30%, 50%, 70%, 90% { - -webkit-transform: translate3d(-10px, 0, 0); - transform: translate3d(-10px, 0, 0); - } - - 20%, 40%, 60%, 80% { - -webkit-transform: translate3d(10px, 0, 0); - transform: translate3d(10px, 0, 0); - } -} - -.shake { - -webkit-animation-name: shake; - animation-name: shake; -} - -@-webkit-keyframes headShake { - 0% { - -webkit-transform: translateX(0); - transform: translateX(0); - } - - 6.5% { - -webkit-transform: translateX(-6px) rotateY(-9deg); - transform: translateX(-6px) rotateY(-9deg); - } - - 18.5% { - -webkit-transform: translateX(5px) rotateY(7deg); - transform: translateX(5px) rotateY(7deg); - } - - 31.5% { - -webkit-transform: translateX(-3px) rotateY(-5deg); - transform: translateX(-3px) rotateY(-5deg); - } - - 43.5% { - -webkit-transform: translateX(2px) rotateY(3deg); - transform: translateX(2px) rotateY(3deg); - } - - 50% { - -webkit-transform: translateX(0); - transform: translateX(0); - } -} - -@keyframes headShake { - 0% { - -webkit-transform: translateX(0); - transform: translateX(0); - } - - 6.5% { - -webkit-transform: translateX(-6px) rotateY(-9deg); - transform: translateX(-6px) rotateY(-9deg); - } - - 18.5% { - -webkit-transform: translateX(5px) rotateY(7deg); - transform: translateX(5px) rotateY(7deg); - } - - 31.5% { - -webkit-transform: translateX(-3px) rotateY(-5deg); - transform: translateX(-3px) rotateY(-5deg); - } - - 43.5% { - -webkit-transform: translateX(2px) rotateY(3deg); - transform: translateX(2px) rotateY(3deg); - } - - 50% { - -webkit-transform: translateX(0); - transform: translateX(0); - } -} - -.headShake { - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - -webkit-animation-name: headShake; - animation-name: headShake; -} - -@-webkit-keyframes swing { - 20% { - -webkit-transform: rotate3d(0, 0, 1, 15deg); - transform: rotate3d(0, 0, 1, 15deg); - } - - 40% { - -webkit-transform: rotate3d(0, 0, 1, -10deg); - transform: rotate3d(0, 0, 1, -10deg); - } - - 60% { - -webkit-transform: rotate3d(0, 0, 1, 5deg); - transform: rotate3d(0, 0, 1, 5deg); - } - - 80% { - -webkit-transform: rotate3d(0, 0, 1, -5deg); - transform: rotate3d(0, 0, 1, -5deg); - } - - to { - -webkit-transform: rotate3d(0, 0, 1, 0deg); - transform: rotate3d(0, 0, 1, 0deg); - } -} - -@keyframes swing { - 20% { - -webkit-transform: rotate3d(0, 0, 1, 15deg); - transform: rotate3d(0, 0, 1, 15deg); - } - - 40% { - -webkit-transform: rotate3d(0, 0, 1, -10deg); - transform: rotate3d(0, 0, 1, -10deg); - } - - 60% { - -webkit-transform: rotate3d(0, 0, 1, 5deg); - transform: rotate3d(0, 0, 1, 5deg); - } - - 80% { - -webkit-transform: rotate3d(0, 0, 1, -5deg); - transform: rotate3d(0, 0, 1, -5deg); - } - - to { - -webkit-transform: rotate3d(0, 0, 1, 0deg); - transform: rotate3d(0, 0, 1, 0deg); - } -} - -.swing { - -webkit-transform-origin: top center; - transform-origin: top center; - -webkit-animation-name: swing; - animation-name: swing; -} - -@-webkit-keyframes tada { - from { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } - - 10%, 20% { - -webkit-transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg); - transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg); - } - - 30%, 50%, 70%, 90% { - -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); - transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); - } - - 40%, 60%, 80% { - -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); - transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); - } - - to { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -@keyframes tada { - from { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } - - 10%, 20% { - -webkit-transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg); - transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg); - } - - 30%, 50%, 70%, 90% { - -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); - transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); - } - - 40%, 60%, 80% { - -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); - transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); - } - - to { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -.tada { - -webkit-animation-name: tada; - animation-name: tada; -} - -/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ - -@-webkit-keyframes wobble { - from { - -webkit-transform: none; - transform: none; - } - - 15% { - -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); - transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); - } - - 30% { - -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); - transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); - } - - 45% { - -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); - transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); - } - - 60% { - -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); - transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); - } - - 75% { - -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); - transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); - } - - to { - -webkit-transform: none; - transform: none; - } -} - -@keyframes wobble { - from { - -webkit-transform: none; - transform: none; - } - - 15% { - -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); - transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); - } - - 30% { - -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); - transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); - } - - 45% { - -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); - transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); - } - - 60% { - -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); - transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); - } - - 75% { - -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); - transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); - } - - to { - -webkit-transform: none; - transform: none; - } -} - -.wobble { - -webkit-animation-name: wobble; - animation-name: wobble; -} - -@-webkit-keyframes jello { - from, 11.1%, to { - -webkit-transform: none; - transform: none; - } - - 22.2% { - -webkit-transform: skewX(-12.5deg) skewY(-12.5deg); - transform: skewX(-12.5deg) skewY(-12.5deg); - } - - 33.3% { - -webkit-transform: skewX(6.25deg) skewY(6.25deg); - transform: skewX(6.25deg) skewY(6.25deg); - } - - 44.4% { - -webkit-transform: skewX(-3.125deg) skewY(-3.125deg); - transform: skewX(-3.125deg) skewY(-3.125deg); - } - - 55.5% { - -webkit-transform: skewX(1.5625deg) skewY(1.5625deg); - transform: skewX(1.5625deg) skewY(1.5625deg); - } - - 66.6% { - -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg); - transform: skewX(-0.78125deg) skewY(-0.78125deg); - } - - 77.7% { - -webkit-transform: skewX(0.390625deg) skewY(0.390625deg); - transform: skewX(0.390625deg) skewY(0.390625deg); - } - - 88.8% { - -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg); - transform: skewX(-0.1953125deg) skewY(-0.1953125deg); - } -} - -@keyframes jello { - from, 11.1%, to { - -webkit-transform: none; - transform: none; - } - - 22.2% { - -webkit-transform: skewX(-12.5deg) skewY(-12.5deg); - transform: skewX(-12.5deg) skewY(-12.5deg); - } - - 33.3% { - -webkit-transform: skewX(6.25deg) skewY(6.25deg); - transform: skewX(6.25deg) skewY(6.25deg); - } - - 44.4% { - -webkit-transform: skewX(-3.125deg) skewY(-3.125deg); - transform: skewX(-3.125deg) skewY(-3.125deg); - } - - 55.5% { - -webkit-transform: skewX(1.5625deg) skewY(1.5625deg); - transform: skewX(1.5625deg) skewY(1.5625deg); - } - - 66.6% { - -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg); - transform: skewX(-0.78125deg) skewY(-0.78125deg); - } - - 77.7% { - -webkit-transform: skewX(0.390625deg) skewY(0.390625deg); - transform: skewX(0.390625deg) skewY(0.390625deg); - } - - 88.8% { - -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg); - transform: skewX(-0.1953125deg) skewY(-0.1953125deg); - } -} - -.jello { - -webkit-animation-name: jello; - animation-name: jello; - -webkit-transform-origin: center; - transform-origin: center; -} - -@-webkit-keyframes bounceIn { - from, 20%, 40%, 60%, 80%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - 0% { - opacity: 0; - -webkit-transform: scale3d(.3, .3, .3); - transform: scale3d(.3, .3, .3); - } - - 20% { - -webkit-transform: scale3d(1.1, 1.1, 1.1); - transform: scale3d(1.1, 1.1, 1.1); - } - - 40% { - -webkit-transform: scale3d(.9, .9, .9); - transform: scale3d(.9, .9, .9); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(1.03, 1.03, 1.03); - transform: scale3d(1.03, 1.03, 1.03); - } - - 80% { - -webkit-transform: scale3d(.97, .97, .97); - transform: scale3d(.97, .97, .97); - } - - to { - opacity: 1; - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -@keyframes bounceIn { - from, 20%, 40%, 60%, 80%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - 0% { - opacity: 0; - -webkit-transform: scale3d(.3, .3, .3); - transform: scale3d(.3, .3, .3); - } - - 20% { - -webkit-transform: scale3d(1.1, 1.1, 1.1); - transform: scale3d(1.1, 1.1, 1.1); - } - - 40% { - -webkit-transform: scale3d(.9, .9, .9); - transform: scale3d(.9, .9, .9); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(1.03, 1.03, 1.03); - transform: scale3d(1.03, 1.03, 1.03); - } - - 80% { - -webkit-transform: scale3d(.97, .97, .97); - transform: scale3d(.97, .97, .97); - } - - to { - opacity: 1; - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -.bounceIn { - -webkit-animation-name: bounceIn; - animation-name: bounceIn; -} - -@-webkit-keyframes bounceInDown { - from, 60%, 75%, 90%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - 0% { - opacity: 0; - -webkit-transform: translate3d(0, -3000px, 0); - transform: translate3d(0, -3000px, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(0, 25px, 0); - transform: translate3d(0, 25px, 0); - } - - 75% { - -webkit-transform: translate3d(0, -10px, 0); - transform: translate3d(0, -10px, 0); - } - - 90% { - -webkit-transform: translate3d(0, 5px, 0); - transform: translate3d(0, 5px, 0); - } - - to { - -webkit-transform: none; - transform: none; - } -} - -@keyframes bounceInDown { - from, 60%, 75%, 90%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - 0% { - opacity: 0; - -webkit-transform: translate3d(0, -3000px, 0); - transform: translate3d(0, -3000px, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(0, 25px, 0); - transform: translate3d(0, 25px, 0); - } - - 75% { - -webkit-transform: translate3d(0, -10px, 0); - transform: translate3d(0, -10px, 0); - } - - 90% { - -webkit-transform: translate3d(0, 5px, 0); - transform: translate3d(0, 5px, 0); - } - - to { - -webkit-transform: none; - transform: none; - } -} - -.bounceInDown { - -webkit-animation-name: bounceInDown; - animation-name: bounceInDown; -} - -@-webkit-keyframes bounceInLeft { - from, 60%, 75%, 90%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - 0% { - opacity: 0; - -webkit-transform: translate3d(-3000px, 0, 0); - transform: translate3d(-3000px, 0, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(25px, 0, 0); - transform: translate3d(25px, 0, 0); - } - - 75% { - -webkit-transform: translate3d(-10px, 0, 0); - transform: translate3d(-10px, 0, 0); - } - - 90% { - -webkit-transform: translate3d(5px, 0, 0); - transform: translate3d(5px, 0, 0); - } - - to { - -webkit-transform: none; - transform: none; - } -} - -@keyframes bounceInLeft { - from, 60%, 75%, 90%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - 0% { - opacity: 0; - -webkit-transform: translate3d(-3000px, 0, 0); - transform: translate3d(-3000px, 0, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(25px, 0, 0); - transform: translate3d(25px, 0, 0); - } - - 75% { - -webkit-transform: translate3d(-10px, 0, 0); - transform: translate3d(-10px, 0, 0); - } - - 90% { - -webkit-transform: translate3d(5px, 0, 0); - transform: translate3d(5px, 0, 0); - } - - to { - -webkit-transform: none; - transform: none; - } -} - -.bounceInLeft { - -webkit-animation-name: bounceInLeft; - animation-name: bounceInLeft; -} - -@-webkit-keyframes bounceInRight { - from, 60%, 75%, 90%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - from { - opacity: 0; - -webkit-transform: translate3d(3000px, 0, 0); - transform: translate3d(3000px, 0, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(-25px, 0, 0); - transform: translate3d(-25px, 0, 0); - } - - 75% { - -webkit-transform: translate3d(10px, 0, 0); - transform: translate3d(10px, 0, 0); - } - - 90% { - -webkit-transform: translate3d(-5px, 0, 0); - transform: translate3d(-5px, 0, 0); - } - - to { - -webkit-transform: none; - transform: none; - } -} - -@keyframes bounceInRight { - from, 60%, 75%, 90%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - from { - opacity: 0; - -webkit-transform: translate3d(3000px, 0, 0); - transform: translate3d(3000px, 0, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(-25px, 0, 0); - transform: translate3d(-25px, 0, 0); - } - - 75% { - -webkit-transform: translate3d(10px, 0, 0); - transform: translate3d(10px, 0, 0); - } - - 90% { - -webkit-transform: translate3d(-5px, 0, 0); - transform: translate3d(-5px, 0, 0); - } - - to { - -webkit-transform: none; - transform: none; - } -} - -.bounceInRight { - -webkit-animation-name: bounceInRight; - animation-name: bounceInRight; -} - -@-webkit-keyframes bounceInUp { - from, 60%, 75%, 90%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - from { - opacity: 0; - -webkit-transform: translate3d(0, 3000px, 0); - transform: translate3d(0, 3000px, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(0, -20px, 0); - transform: translate3d(0, -20px, 0); - } - - 75% { - -webkit-transform: translate3d(0, 10px, 0); - transform: translate3d(0, 10px, 0); - } - - 90% { - -webkit-transform: translate3d(0, -5px, 0); - transform: translate3d(0, -5px, 0); - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes bounceInUp { - from, 60%, 75%, 90%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - from { - opacity: 0; - -webkit-transform: translate3d(0, 3000px, 0); - transform: translate3d(0, 3000px, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(0, -20px, 0); - transform: translate3d(0, -20px, 0); - } - - 75% { - -webkit-transform: translate3d(0, 10px, 0); - transform: translate3d(0, 10px, 0); - } - - 90% { - -webkit-transform: translate3d(0, -5px, 0); - transform: translate3d(0, -5px, 0); - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.bounceInUp { - -webkit-animation-name: bounceInUp; - animation-name: bounceInUp; -} - -@-webkit-keyframes bounceOut { - 20% { - -webkit-transform: scale3d(.9, .9, .9); - transform: scale3d(.9, .9, .9); - } - - 50%, 55% { - opacity: 1; - -webkit-transform: scale3d(1.1, 1.1, 1.1); - transform: scale3d(1.1, 1.1, 1.1); - } - - to { - opacity: 0; - -webkit-transform: scale3d(.3, .3, .3); - transform: scale3d(.3, .3, .3); - } -} - -@keyframes bounceOut { - 20% { - -webkit-transform: scale3d(.9, .9, .9); - transform: scale3d(.9, .9, .9); - } - - 50%, 55% { - opacity: 1; - -webkit-transform: scale3d(1.1, 1.1, 1.1); - transform: scale3d(1.1, 1.1, 1.1); - } - - to { - opacity: 0; - -webkit-transform: scale3d(.3, .3, .3); - transform: scale3d(.3, .3, .3); - } -} - -.bounceOut { - -webkit-animation-name: bounceOut; - animation-name: bounceOut; -} - -@-webkit-keyframes bounceOutDown { - 20% { - -webkit-transform: translate3d(0, 10px, 0); - transform: translate3d(0, 10px, 0); - } - - 40%, 45% { - opacity: 1; - -webkit-transform: translate3d(0, -20px, 0); - transform: translate3d(0, -20px, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 2000px, 0); - transform: translate3d(0, 2000px, 0); - } -} - -@keyframes bounceOutDown { - 20% { - -webkit-transform: translate3d(0, 10px, 0); - transform: translate3d(0, 10px, 0); - } - - 40%, 45% { - opacity: 1; - -webkit-transform: translate3d(0, -20px, 0); - transform: translate3d(0, -20px, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 2000px, 0); - transform: translate3d(0, 2000px, 0); - } -} - -.bounceOutDown { - -webkit-animation-name: bounceOutDown; - animation-name: bounceOutDown; -} - -@-webkit-keyframes bounceOutLeft { - 20% { - opacity: 1; - -webkit-transform: translate3d(20px, 0, 0); - transform: translate3d(20px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(-2000px, 0, 0); - transform: translate3d(-2000px, 0, 0); - } -} - -@keyframes bounceOutLeft { - 20% { - opacity: 1; - -webkit-transform: translate3d(20px, 0, 0); - transform: translate3d(20px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(-2000px, 0, 0); - transform: translate3d(-2000px, 0, 0); - } -} - -.bounceOutLeft { - -webkit-animation-name: bounceOutLeft; - animation-name: bounceOutLeft; -} - -@-webkit-keyframes bounceOutRight { - 20% { - opacity: 1; - -webkit-transform: translate3d(-20px, 0, 0); - transform: translate3d(-20px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(2000px, 0, 0); - transform: translate3d(2000px, 0, 0); - } -} - -@keyframes bounceOutRight { - 20% { - opacity: 1; - -webkit-transform: translate3d(-20px, 0, 0); - transform: translate3d(-20px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(2000px, 0, 0); - transform: translate3d(2000px, 0, 0); - } -} - -.bounceOutRight { - -webkit-animation-name: bounceOutRight; - animation-name: bounceOutRight; -} - -@-webkit-keyframes bounceOutUp { - 20% { - -webkit-transform: translate3d(0, -10px, 0); - transform: translate3d(0, -10px, 0); - } - - 40%, 45% { - opacity: 1; - -webkit-transform: translate3d(0, 20px, 0); - transform: translate3d(0, 20px, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -2000px, 0); - transform: translate3d(0, -2000px, 0); - } -} - -@keyframes bounceOutUp { - 20% { - -webkit-transform: translate3d(0, -10px, 0); - transform: translate3d(0, -10px, 0); - } - - 40%, 45% { - opacity: 1; - -webkit-transform: translate3d(0, 20px, 0); - transform: translate3d(0, 20px, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -2000px, 0); - transform: translate3d(0, -2000px, 0); - } -} - -.bounceOutUp { - -webkit-animation-name: bounceOutUp; - animation-name: bounceOutUp; -} - -@-webkit-keyframes fadeIn { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} - -@keyframes fadeIn { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} - -.fadeIn { - -webkit-animation-name: fadeIn; - animation-name: fadeIn; -} - -@-webkit-keyframes fadeInDown { - from { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInDown { - from { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.fadeInDown { - -webkit-animation-name: fadeInDown; - animation-name: fadeInDown; -} - -@-webkit-keyframes fadeInDownBig { - from { - opacity: 0; - -webkit-transform: translate3d(0, -2000px, 0); - transform: translate3d(0, -2000px, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInDownBig { - from { - opacity: 0; - -webkit-transform: translate3d(0, -2000px, 0); - transform: translate3d(0, -2000px, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.fadeInDownBig { - -webkit-animation-name: fadeInDownBig; - animation-name: fadeInDownBig; -} - -@-webkit-keyframes fadeInLeft { - from { - opacity: 0; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInLeft { - from { - opacity: 0; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.fadeInLeft { - -webkit-animation-name: fadeInLeft; - animation-name: fadeInLeft; -} - -@-webkit-keyframes fadeInLeftBig { - from { - opacity: 0; - -webkit-transform: translate3d(-2000px, 0, 0); - transform: translate3d(-2000px, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInLeftBig { - from { - opacity: 0; - -webkit-transform: translate3d(-2000px, 0, 0); - transform: translate3d(-2000px, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.fadeInLeftBig { - -webkit-animation-name: fadeInLeftBig; - animation-name: fadeInLeftBig; -} - -@-webkit-keyframes fadeInRight { - from { - opacity: 0; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInRight { - from { - opacity: 0; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.fadeInRight { - -webkit-animation-name: fadeInRight; - animation-name: fadeInRight; -} - -@-webkit-keyframes fadeInRightBig { - from { - opacity: 0; - -webkit-transform: translate3d(2000px, 0, 0); - transform: translate3d(2000px, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInRightBig { - from { - opacity: 0; - -webkit-transform: translate3d(2000px, 0, 0); - transform: translate3d(2000px, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.fadeInRightBig { - -webkit-animation-name: fadeInRightBig; - animation-name: fadeInRightBig; -} - -@-webkit-keyframes fadeInUp { - from { - opacity: 0; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInUp { - from { - opacity: 0; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.fadeInUp { - -webkit-animation-name: fadeInUp; - animation-name: fadeInUp; -} - -@-webkit-keyframes fadeInUpBig { - from { - opacity: 0; - -webkit-transform: translate3d(0, 2000px, 0); - transform: translate3d(0, 2000px, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInUpBig { - from { - opacity: 0; - -webkit-transform: translate3d(0, 2000px, 0); - transform: translate3d(0, 2000px, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.fadeInUpBig { - -webkit-animation-name: fadeInUpBig; - animation-name: fadeInUpBig; -} - -@-webkit-keyframes fadeOut { - from { - opacity: 1; - } - - to { - opacity: 0; - } -} - -@keyframes fadeOut { - from { - opacity: 1; - } - - to { - opacity: 0; - } -} - -.fadeOut { - -webkit-animation-name: fadeOut; - animation-name: fadeOut; -} - -@-webkit-keyframes fadeOutDown { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } -} - -@keyframes fadeOutDown { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } -} - -.fadeOutDown { - -webkit-animation-name: fadeOutDown; - animation-name: fadeOutDown; -} - -@-webkit-keyframes fadeOutDownBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 2000px, 0); - transform: translate3d(0, 2000px, 0); - } -} - -@keyframes fadeOutDownBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 2000px, 0); - transform: translate3d(0, 2000px, 0); - } -} - -.fadeOutDownBig { - -webkit-animation-name: fadeOutDownBig; - animation-name: fadeOutDownBig; -} - -@-webkit-keyframes fadeOutLeft { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } -} - -@keyframes fadeOutLeft { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } -} - -.fadeOutLeft { - -webkit-animation-name: fadeOutLeft; - animation-name: fadeOutLeft; -} - -@-webkit-keyframes fadeOutLeftBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(-2000px, 0, 0); - transform: translate3d(-2000px, 0, 0); - } -} - -@keyframes fadeOutLeftBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(-2000px, 0, 0); - transform: translate3d(-2000px, 0, 0); - } -} - -.fadeOutLeftBig { - -webkit-animation-name: fadeOutLeftBig; - animation-name: fadeOutLeftBig; -} - -@-webkit-keyframes fadeOutRight { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } -} - -@keyframes fadeOutRight { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } -} - -.fadeOutRight { - -webkit-animation-name: fadeOutRight; - animation-name: fadeOutRight; -} - -@-webkit-keyframes fadeOutRightBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(2000px, 0, 0); - transform: translate3d(2000px, 0, 0); - } -} - -@keyframes fadeOutRightBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(2000px, 0, 0); - transform: translate3d(2000px, 0, 0); - } -} - -.fadeOutRightBig { - -webkit-animation-name: fadeOutRightBig; - animation-name: fadeOutRightBig; -} - -@-webkit-keyframes fadeOutUp { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } -} - -@keyframes fadeOutUp { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } -} - -.fadeOutUp { - -webkit-animation-name: fadeOutUp; - animation-name: fadeOutUp; -} - -@-webkit-keyframes fadeOutUpBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -2000px, 0); - transform: translate3d(0, -2000px, 0); - } -} - -@keyframes fadeOutUpBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -2000px, 0); - transform: translate3d(0, -2000px, 0); - } -} - -.fadeOutUpBig { - -webkit-animation-name: fadeOutUpBig; - animation-name: fadeOutUpBig; -} - -@-webkit-keyframes flip { - from { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg); - transform: perspective(400px) rotate3d(0, 1, 0, -360deg); - -webkit-animation-timing-function: ease-out; - animation-timing-function: ease-out; - } - - 40% { - -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); - transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); - -webkit-animation-timing-function: ease-out; - animation-timing-function: ease-out; - } - - 50% { - -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); - transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - 80% { - -webkit-transform: perspective(400px) scale3d(.95, .95, .95); - transform: perspective(400px) scale3d(.95, .95, .95); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - to { - -webkit-transform: perspective(400px); - transform: perspective(400px); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } -} - -@keyframes flip { - from { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg); - transform: perspective(400px) rotate3d(0, 1, 0, -360deg); - -webkit-animation-timing-function: ease-out; - animation-timing-function: ease-out; - } - - 40% { - -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); - transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); - -webkit-animation-timing-function: ease-out; - animation-timing-function: ease-out; - } - - 50% { - -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); - transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - 80% { - -webkit-transform: perspective(400px) scale3d(.95, .95, .95); - transform: perspective(400px) scale3d(.95, .95, .95); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - to { - -webkit-transform: perspective(400px); - transform: perspective(400px); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } -} - -.animated.flip { - -webkit-backface-visibility: visible; - backface-visibility: visible; - -webkit-animation-name: flip; - animation-name: flip; -} - -@-webkit-keyframes flipInX { - from { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - opacity: 0; - } - - 40% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - 60% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg); - transform: perspective(400px) rotate3d(1, 0, 0, 10deg); - opacity: 1; - } - - 80% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg); - transform: perspective(400px) rotate3d(1, 0, 0, -5deg); - } - - to { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } -} - -@keyframes flipInX { - from { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - opacity: 0; - } - - 40% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - 60% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg); - transform: perspective(400px) rotate3d(1, 0, 0, 10deg); - opacity: 1; - } - - 80% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg); - transform: perspective(400px) rotate3d(1, 0, 0, -5deg); - } - - to { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } -} - -.flipInX { - -webkit-backface-visibility: visible !important; - backface-visibility: visible !important; - -webkit-animation-name: flipInX; - animation-name: flipInX; -} - -@-webkit-keyframes flipInY { - from { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - opacity: 0; - } - - 40% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg); - transform: perspective(400px) rotate3d(0, 1, 0, -20deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - 60% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg); - transform: perspective(400px) rotate3d(0, 1, 0, 10deg); - opacity: 1; - } - - 80% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg); - transform: perspective(400px) rotate3d(0, 1, 0, -5deg); - } - - to { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } -} - -@keyframes flipInY { - from { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - opacity: 0; - } - - 40% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg); - transform: perspective(400px) rotate3d(0, 1, 0, -20deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - 60% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg); - transform: perspective(400px) rotate3d(0, 1, 0, 10deg); - opacity: 1; - } - - 80% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg); - transform: perspective(400px) rotate3d(0, 1, 0, -5deg); - } - - to { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } -} - -.flipInY { - -webkit-backface-visibility: visible !important; - backface-visibility: visible !important; - -webkit-animation-name: flipInY; - animation-name: flipInY; -} - -@-webkit-keyframes flipOutX { - from { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } - - 30% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - opacity: 1; - } - - to { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - opacity: 0; - } -} - -@keyframes flipOutX { - from { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } - - 30% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - opacity: 1; - } - - to { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - opacity: 0; - } -} - -.flipOutX { - -webkit-animation-name: flipOutX; - animation-name: flipOutX; - -webkit-backface-visibility: visible !important; - backface-visibility: visible !important; -} - -@-webkit-keyframes flipOutY { - from { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } - - 30% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg); - transform: perspective(400px) rotate3d(0, 1, 0, -15deg); - opacity: 1; - } - - to { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - opacity: 0; - } -} - -@keyframes flipOutY { - from { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } - - 30% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg); - transform: perspective(400px) rotate3d(0, 1, 0, -15deg); - opacity: 1; - } - - to { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - opacity: 0; - } -} - -.flipOutY { - -webkit-backface-visibility: visible !important; - backface-visibility: visible !important; - -webkit-animation-name: flipOutY; - animation-name: flipOutY; -} - -@-webkit-keyframes lightSpeedIn { - from { - -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg); - transform: translate3d(100%, 0, 0) skewX(-30deg); - opacity: 0; - } - - 60% { - -webkit-transform: skewX(20deg); - transform: skewX(20deg); - opacity: 1; - } - - 80% { - -webkit-transform: skewX(-5deg); - transform: skewX(-5deg); - opacity: 1; - } - - to { - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -@keyframes lightSpeedIn { - from { - -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg); - transform: translate3d(100%, 0, 0) skewX(-30deg); - opacity: 0; - } - - 60% { - -webkit-transform: skewX(20deg); - transform: skewX(20deg); - opacity: 1; - } - - 80% { - -webkit-transform: skewX(-5deg); - transform: skewX(-5deg); - opacity: 1; - } - - to { - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -.lightSpeedIn { - -webkit-animation-name: lightSpeedIn; - animation-name: lightSpeedIn; - -webkit-animation-timing-function: ease-out; - animation-timing-function: ease-out; -} - -@-webkit-keyframes lightSpeedOut { - from { - opacity: 1; - } - - to { - -webkit-transform: translate3d(100%, 0, 0) skewX(30deg); - transform: translate3d(100%, 0, 0) skewX(30deg); - opacity: 0; - } -} - -@keyframes lightSpeedOut { - from { - opacity: 1; - } - - to { - -webkit-transform: translate3d(100%, 0, 0) skewX(30deg); - transform: translate3d(100%, 0, 0) skewX(30deg); - opacity: 0; - } -} - -.lightSpeedOut { - -webkit-animation-name: lightSpeedOut; - animation-name: lightSpeedOut; - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; -} - -@-webkit-keyframes rotateIn { - from { - -webkit-transform-origin: center; - transform-origin: center; - -webkit-transform: rotate3d(0, 0, 1, -200deg); - transform: rotate3d(0, 0, 1, -200deg); - opacity: 0; - } - - to { - -webkit-transform-origin: center; - transform-origin: center; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -@keyframes rotateIn { - from { - -webkit-transform-origin: center; - transform-origin: center; - -webkit-transform: rotate3d(0, 0, 1, -200deg); - transform: rotate3d(0, 0, 1, -200deg); - opacity: 0; - } - - to { - -webkit-transform-origin: center; - transform-origin: center; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -.rotateIn { - -webkit-animation-name: rotateIn; - animation-name: rotateIn; -} - -@-webkit-keyframes rotateInDownLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, -45deg); - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -@keyframes rotateInDownLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, -45deg); - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -.rotateInDownLeft { - -webkit-animation-name: rotateInDownLeft; - animation-name: rotateInDownLeft; -} - -@-webkit-keyframes rotateInDownRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, 45deg); - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -@keyframes rotateInDownRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, 45deg); - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -.rotateInDownRight { - -webkit-animation-name: rotateInDownRight; - animation-name: rotateInDownRight; -} - -@-webkit-keyframes rotateInUpLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, 45deg); - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -@keyframes rotateInUpLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, 45deg); - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -.rotateInUpLeft { - -webkit-animation-name: rotateInUpLeft; - animation-name: rotateInUpLeft; -} - -@-webkit-keyframes rotateInUpRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, -90deg); - transform: rotate3d(0, 0, 1, -90deg); - opacity: 0; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -@keyframes rotateInUpRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, -90deg); - transform: rotate3d(0, 0, 1, -90deg); - opacity: 0; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -.rotateInUpRight { - -webkit-animation-name: rotateInUpRight; - animation-name: rotateInUpRight; -} - -@-webkit-keyframes rotateOut { - from { - -webkit-transform-origin: center; - transform-origin: center; - opacity: 1; - } - - to { - -webkit-transform-origin: center; - transform-origin: center; - -webkit-transform: rotate3d(0, 0, 1, 200deg); - transform: rotate3d(0, 0, 1, 200deg); - opacity: 0; - } -} - -@keyframes rotateOut { - from { - -webkit-transform-origin: center; - transform-origin: center; - opacity: 1; - } - - to { - -webkit-transform-origin: center; - transform-origin: center; - -webkit-transform: rotate3d(0, 0, 1, 200deg); - transform: rotate3d(0, 0, 1, 200deg); - opacity: 0; - } -} - -.rotateOut { - -webkit-animation-name: rotateOut; - animation-name: rotateOut; -} - -@-webkit-keyframes rotateOutDownLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, 45deg); - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } -} - -@keyframes rotateOutDownLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, 45deg); - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } -} - -.rotateOutDownLeft { - -webkit-animation-name: rotateOutDownLeft; - animation-name: rotateOutDownLeft; -} - -@-webkit-keyframes rotateOutDownRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, -45deg); - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } -} - -@keyframes rotateOutDownRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, -45deg); - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } -} - -.rotateOutDownRight { - -webkit-animation-name: rotateOutDownRight; - animation-name: rotateOutDownRight; -} - -@-webkit-keyframes rotateOutUpLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, -45deg); - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } -} - -@keyframes rotateOutUpLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, -45deg); - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } -} - -.rotateOutUpLeft { - -webkit-animation-name: rotateOutUpLeft; - animation-name: rotateOutUpLeft; -} - -@-webkit-keyframes rotateOutUpRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, 90deg); - transform: rotate3d(0, 0, 1, 90deg); - opacity: 0; - } -} - -@keyframes rotateOutUpRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, 90deg); - transform: rotate3d(0, 0, 1, 90deg); - opacity: 0; - } -} - -.rotateOutUpRight { - -webkit-animation-name: rotateOutUpRight; - animation-name: rotateOutUpRight; -} - -@-webkit-keyframes hinge { - 0% { - -webkit-transform-origin: top left; - transform-origin: top left; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - } - - 20%, 60% { - -webkit-transform: rotate3d(0, 0, 1, 80deg); - transform: rotate3d(0, 0, 1, 80deg); - -webkit-transform-origin: top left; - transform-origin: top left; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - } - - 40%, 80% { - -webkit-transform: rotate3d(0, 0, 1, 60deg); - transform: rotate3d(0, 0, 1, 60deg); - -webkit-transform-origin: top left; - transform-origin: top left; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - opacity: 1; - } - - to { - -webkit-transform: translate3d(0, 700px, 0); - transform: translate3d(0, 700px, 0); - opacity: 0; - } -} - -@keyframes hinge { - 0% { - -webkit-transform-origin: top left; - transform-origin: top left; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - } - - 20%, 60% { - -webkit-transform: rotate3d(0, 0, 1, 80deg); - transform: rotate3d(0, 0, 1, 80deg); - -webkit-transform-origin: top left; - transform-origin: top left; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - } - - 40%, 80% { - -webkit-transform: rotate3d(0, 0, 1, 60deg); - transform: rotate3d(0, 0, 1, 60deg); - -webkit-transform-origin: top left; - transform-origin: top left; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - opacity: 1; - } - - to { - -webkit-transform: translate3d(0, 700px, 0); - transform: translate3d(0, 700px, 0); - opacity: 0; - } -} - -.hinge { - -webkit-animation-name: hinge; - animation-name: hinge; -} - -/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ - -@-webkit-keyframes rollIn { - from { - opacity: 0; - -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); - transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes rollIn { - from { - opacity: 0; - -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); - transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.rollIn { - -webkit-animation-name: rollIn; - animation-name: rollIn; -} - -/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ - -@-webkit-keyframes rollOut { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); - transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); - } -} - -@keyframes rollOut { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); - transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); - } -} - -.rollOut { - -webkit-animation-name: rollOut; - animation-name: rollOut; -} - -@-webkit-keyframes zoomIn { - from { - opacity: 0; - -webkit-transform: scale3d(.3, .3, .3); - transform: scale3d(.3, .3, .3); - } - - 50% { - opacity: 1; - } -} - -@keyframes zoomIn { - from { - opacity: 0; - -webkit-transform: scale3d(.3, .3, .3); - transform: scale3d(.3, .3, .3); - } - - 50% { - opacity: 1; - } -} - -.zoomIn { - -webkit-animation-name: zoomIn; - animation-name: zoomIn; -} - -@-webkit-keyframes zoomInDown { - from { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0); - transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); - transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -@keyframes zoomInDown { - from { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0); - transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); - transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -.zoomInDown { - -webkit-animation-name: zoomInDown; - animation-name: zoomInDown; -} - -@-webkit-keyframes zoomInLeft { - from { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0); - transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0); - transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -@keyframes zoomInLeft { - from { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0); - transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0); - transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -.zoomInLeft { - -webkit-animation-name: zoomInLeft; - animation-name: zoomInLeft; -} - -@-webkit-keyframes zoomInRight { - from { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0); - transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0); - transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -@keyframes zoomInRight { - from { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0); - transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0); - transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -.zoomInRight { - -webkit-animation-name: zoomInRight; - animation-name: zoomInRight; -} - -@-webkit-keyframes zoomInUp { - from { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0); - transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); - transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -@keyframes zoomInUp { - from { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0); - transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); - transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -.zoomInUp { - -webkit-animation-name: zoomInUp; - animation-name: zoomInUp; -} - -@-webkit-keyframes zoomOut { - from { - opacity: 1; - } - - 50% { - opacity: 0; - -webkit-transform: scale3d(.3, .3, .3); - transform: scale3d(.3, .3, .3); - } - - to { - opacity: 0; - } -} - -@keyframes zoomOut { - from { - opacity: 1; - } - - 50% { - opacity: 0; - -webkit-transform: scale3d(.3, .3, .3); - transform: scale3d(.3, .3, .3); - } - - to { - opacity: 0; - } -} - -.zoomOut { - -webkit-animation-name: zoomOut; - animation-name: zoomOut; -} - -@-webkit-keyframes zoomOutDown { - 40% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); - transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - to { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0); - transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0); - -webkit-transform-origin: center bottom; - transform-origin: center bottom; - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -@keyframes zoomOutDown { - 40% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); - transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - to { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0); - transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0); - -webkit-transform-origin: center bottom; - transform-origin: center bottom; - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -.zoomOutDown { - -webkit-animation-name: zoomOutDown; - animation-name: zoomOutDown; -} - -@-webkit-keyframes zoomOutLeft { - 40% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0); - transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: scale(.1) translate3d(-2000px, 0, 0); - transform: scale(.1) translate3d(-2000px, 0, 0); - -webkit-transform-origin: left center; - transform-origin: left center; - } -} - -@keyframes zoomOutLeft { - 40% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0); - transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: scale(.1) translate3d(-2000px, 0, 0); - transform: scale(.1) translate3d(-2000px, 0, 0); - -webkit-transform-origin: left center; - transform-origin: left center; - } -} - -.zoomOutLeft { - -webkit-animation-name: zoomOutLeft; - animation-name: zoomOutLeft; -} - -@-webkit-keyframes zoomOutRight { - 40% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0); - transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: scale(.1) translate3d(2000px, 0, 0); - transform: scale(.1) translate3d(2000px, 0, 0); - -webkit-transform-origin: right center; - transform-origin: right center; - } -} - -@keyframes zoomOutRight { - 40% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0); - transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: scale(.1) translate3d(2000px, 0, 0); - transform: scale(.1) translate3d(2000px, 0, 0); - -webkit-transform-origin: right center; - transform-origin: right center; - } -} - -.zoomOutRight { - -webkit-animation-name: zoomOutRight; - animation-name: zoomOutRight; -} - -@-webkit-keyframes zoomOutUp { - 40% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); - transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - to { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0); - transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0); - -webkit-transform-origin: center bottom; - transform-origin: center bottom; - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -@keyframes zoomOutUp { - 40% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); - transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - to { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0); - transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0); - -webkit-transform-origin: center bottom; - transform-origin: center bottom; - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -.zoomOutUp { - -webkit-animation-name: zoomOutUp; - animation-name: zoomOutUp; -} - -@-webkit-keyframes slideInDown { - from { - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes slideInDown { - from { - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.slideInDown { - -webkit-animation-name: slideInDown; - animation-name: slideInDown; -} - -@-webkit-keyframes slideInLeft { - from { - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes slideInLeft { - from { - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.slideInLeft { - -webkit-animation-name: slideInLeft; - animation-name: slideInLeft; -} - -@-webkit-keyframes slideInRight { - from { - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes slideInRight { - from { - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.slideInRight { - -webkit-animation-name: slideInRight; - animation-name: slideInRight; -} - -@-webkit-keyframes slideInUp { - from { - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes slideInUp { - from { - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.slideInUp { - -webkit-animation-name: slideInUp; - animation-name: slideInUp; -} - -@-webkit-keyframes slideOutDown { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } -} - -@keyframes slideOutDown { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } -} - -.slideOutDown { - -webkit-animation-name: slideOutDown; - animation-name: slideOutDown; -} - -@-webkit-keyframes slideOutLeft { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } -} - -@keyframes slideOutLeft { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } -} - -.slideOutLeft { - -webkit-animation-name: slideOutLeft; - animation-name: slideOutLeft; -} - -@-webkit-keyframes slideOutRight { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } -} - -@keyframes slideOutRight { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } -} - -.slideOutRight { - -webkit-animation-name: slideOutRight; - animation-name: slideOutRight; -} - -@-webkit-keyframes slideOutUp { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } -} - -@keyframes slideOutUp { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } -} - -.slideOutUp { - -webkit-animation-name: slideOutUp; - animation-name: slideOutUp; -} diff --git a/static/kevin-master/assets/css/getHTMLMediaElement.css b/static/kevin-master/assets/css/getHTMLMediaElement.css deleted file mode 100644 index d678453..0000000 --- a/static/kevin-master/assets/css/getHTMLMediaElement.css +++ /dev/null @@ -1,163 +0,0 @@ -/* -Muaz Khan - www.MuazKhan.com -MIT License - www.WebRTC-Experiment.com/licence -Documentation - github.com/muaz-khan/WebRTC-Experiment/tree/master/getMediaElement -*/ - -.media-container, .media-container * { - margin: 0; - padding: 0; - -webkit-user-select: none; - -moz-user-select: none; - -o-user-select: none; - user-select: none; -} - -.media-container, .media-container * { - -moz-transition: all .5s ease-in-out; - -ms-transition: all .5s ease-in-out; - -o-transition: all .5s ease-in-out; - -webkit-transition: all .5s ease-in-out; - transition: all .5s ease-in-out; -} - -.media-container { - width: 33%; - display: inline-block; - border: 1px solid rgb(0, 0, 0); - border-radius: 4px; - overflow: hidden; - vertical-align: top; - background: white; -} - -.media-box { - background: black; - border: 1px solid rgb(107, 107, 107); - margin: 1px; -} - -.media-controls, .volume-control { - margin-top: 2px; - position: absolute; - margin-left: 5px; - z-index: 100; - opacity: 0; -} - -.media-controls .control, .volume-control .control { - width: 35px; - height: 35px; - background-position: center center; - background-repeat: no-repeat; - float: left; - background-color: rgba(255, 255, 255, 0.84); -} - -.media-controls .control:first-child { - border-bottom-left-radius: 5px; -} - -.volume-control .control:first-child { - border-top-left-radius: 5px; -} - -.media-controls .control:hover, .media-controls .selected, .volume-control .control:hover { - background-color: rgba(255, 255, 255, 0.74); -} - -.media-controls .control:active, .media-container .selected, .volume-control .control:active { - background-color: rgba(255, 255, 255, 0.44)!important; -} - -.mute-audio { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAACsUlEQVRYR92Xu2siURTGp0hnJRgVGVNtEcHOiI2taWIa3Vgpgu4qiKBoCpOgxgdofD8QTFYUXMRSRLstt9xyy/0Tttxyi9kz17mXq7majFED+8EH+p2Zub+5j4NygiC8q/8PDQaDn9LHw6rf739Sq9UCthQfRk9PT2Rg7Ha7/U0q71erA2OXy+X9AgQ/B3KsgbFZADc3N25clyL5SiaTKnqgdW40Gs8A4vE4ARD9+Pj4XSq9Ts1m8xf9gE0uFosIYDwezyaTCXnjVqvVpq+T4oWur6/5UChEiuFweOkinL/GeAnoDD0ENJ1Of7ByTqFQ8HQB+/7+vi3WWbV1fnh4eAYgWsxEQb8gWSQS+YjCk5MTJkA2m5UNUK1WyR4olUq/cW6z2cJidn5+foSz09PTBYBer2cCpNNp2QC1Wm1pE9I1WIIz8BGAoe+xWEwYjUY8p9PpmAB3d3dbLwEWvOUHXHO73WdiZjAYrDiDE8JzWq2WCZBKpWQDwNstAXg8HgJgtVoRgN1uJwAul2v9DGwDsDoD0D8IALw5AnA6nQTg8vKS5zQazc72QKVSWQIIBAIEwGw2IwCHw0EALi4ueE6lUjEB8vn8m2fAYrEQgKurKwRgMpkIgN/v58UBmAC5XE42wOopgGeQGswOAlAqlQggGAwKnU6H546Pj5kA8DZvApjP56QPGI1G1Aeg65I+AHtv0QfWnQLo67IBYNkQQK/Xm9H5bDZDANBzCACs/wIApoIJgIogVm2dWa0Yms1X9CAQnUvRy6JvesmFQoEsgfhd+ohEXxeNRstS/DrRN29yt9td2oRY9DVer1fe7wEsn89npx/Ecr1e3wiQSCT+StH2ogdcdSaTYQLsXMPh8A8LgPWTbG+CM29cBZBKh9Xt7e0XOPfvM/hOxPrHekgzw8NZ4P4BtGizy4jmqy8AAAAASUVORK5CYII='); -} - -.unmute-audio { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAACY0lEQVRYR9WXS2/aQBDHfa9POaDGhKTpgTNIfICohfI4wC0HDuWdOCWQBKy24hmUBqduAjgVhx4Q50oIPk0/TQ/urhlbNplFEcWu+pd+EjszO7OyZweZ0zTtn4Ia3QQ1uslWNJ1OVVmWtU6n8xpM7ikSiVQ8Ho9mAGbnlcvlDq2FXT1AvV7/jRWnQIgzGg2GC6yoFQjdvsJv3ipYwVUgfHuKRt4dYYVYwLbnKxaL7WCJsu8zvHzbF8ST0ye+dUDa56vdbqOJvLsCrw5HwtXFJepnAWl1kdkgEU5gaUpRlGPCjb4gwwNNdHjwir9XvgnV8wrqZ6EnJQoGgynDlkgkjsDMpVKpgGEPBAIZTpIkWwID+gS+yndC+ewD6mcBdWhe8wCUeDzuTSaTL6y2QqGQ4brdrmmw4vPu8cOHgXBRqaJ+FlBfV7lclrAYSj6fX76CRqOBBhz49vnv6qNQu7xC/Sz0pBaRofVjNUYUxZ/g5rher2dzGuzv+XgyeDbuAavWxjSbTZvTgB6ANmGlfI76WUBaU1gMBdwc12q10ADh5S5/15eFs1MR9bOAtLpI99t6oFarmb+j0eiyB1gHoE04uH/YuAnT6bTtFhSLRS9pStstIFcywxxE9Ak8jtSNB1E4HDYPUCqVzDlQrVbNORAKhTLMJ0B74G9vwWKxkAhPJuF8Pj8mLF9BNpvdIdiSfP74SbvudPnbmy/O/xes02w2E/r9PlqIBWzdrsjgKGHFMGCLM8IKrgKhzmkymfzCChtAmPNi3R5wuyNyp6PW4n6/3/0PE6rxeKwSYrD8z4R9MLqHxv0BTZnWtpv+sYEAAAAASUVORK5CYII='); -} - -.mute-video { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwQAADsEBuJFr7QAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAABoElEQVRYR2NgGAWDNARSge4qJxL7UN0PfHx8O5iZmW8CDSYGd1HdAXJycns4ODjuAQ3Ghz8D5f8D8SKqO0BfXz+Ll5e3FmgwPnyelg7gADqAE2gBPryEZg4gMkgXUtsBTEAD2UjAi6EOAIUEsj5GZA8A0xOTpKQkNnOZ0T0qCRRIJAEfhTrgGJoeQTQHSAMdgM1cY3QH2AAFXpOAf0AdAKKR9WmCDO7q6hIPCgrSEhISShQREcFmbg26AxyhBoKyFiVYF2RwW1tbrr+//zEWFpZrQIzNvDaaOsDGxqZdWVn5GyMj408cHqKNA9jY2EqApWg4Dw/PZk5OTnwhSTMHnGZiYjoA9PVjAlFJGweA4hsY7MSkIdo4gIQEPOqAYRoCwBxATAIEqaFNCADLgcdAR9wFWvBhQLIhOzt7K7AgygE6Yi+B0KBNCAAttQA6gNfAwGASsCqmf0kIDHZwZZSTk1Po4OBwBlgw3SK2MiK1OsZVdcOqYwNgdRzOzc3dyM/PT1R1rAJ0eB8VMKhhAwfAaNAANkiwmeuNXh2P8kdmCAAAkSPyEJegDaEAAAAASUVORK5CYII='); -} - -.unmute-video { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwQAADsEBuJFr7QAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAACFUlEQVRYR2NgGIFgPtDPGQPlb5Dl/4H4PRBL4HNEKlCynEjsQ6RvYJZ/B6p3wKuHj49vBzMz802gImJwFxEOaID6HGS5B0H1cnJyezg4OO4BFeLDn6GGLiJgIGmWgwzT19fP4uXlrQUy8eHzRDigAKoGFO8RBH0OUwB0AAfQAZxAPj68hIADEpAsB7GpDhbicQCy5RXE2swEVMhGAl4MdQAoJJD1JSL5vAGYnpgkJSWxmcuM7jBJoABIM7H4KNSiY0h6+oDsH1DxBpAFQAdIAx2AzUxjdAfYAAVek4BhFoFokL6PQPwPZnlXV5d4UFCQlpCQUKKIiAg2c2vQHeCIFHSgVEsungMyuK2tLdff3/8YCwvLNSDGZlYbrRygCzLYxsamXVlZ+RsjI+NPHJ6hjQPY2NhKgKVoOA8Pz2ZOTk58oUgzB5xmYmI6APT1YwLRSBsHgOIbGOzEpB/aOICExDvqgGEaAsAcQEwCBKmhTQgAy4HHQEfcBVrwYUCyITs7eyuwIMoBOmIvgdCgTQgALbUAOoDXwMBgErAmpH9JCAx2cF2Qk5NT6ODgcAZYMN0itjKCVceglivI5aCqFdR+J6WKBqnVBDkAWB0bAKvjcG5u7kZ+fn6iqmMVoL4rUMt/A2lQiwfUwCAVgxo2cACMBg1ggwSbGd7o1fF0qOXEtd3RdVPIbxixloMCDpZViO84UBjcyNoBhLMZ3JbarLEAAAAASUVORK5CYII='); -} - -.record-audio { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAACuUlEQVRYR72WTW8SURiFm9jquiGFhXahdWWl9bMWozQhIUaBahA/0spGKli1VC0EaqpSUIpWksoELcwaQrBCWLl073/xN4z3JXfIncuBIUZ8krOYM/e9z2SGCTOiaRqMGc1m81CtVsuUSqWMqqpTvO4L9KCS0o9qtXpgtVo1Ofx0T6AHlZReZDKZXSTX4/f7J/nSLqAHlRREOByeRlI5fHkX0INKCsLn891EQjnFYvEaHzEAPaikmCFL8/m86RD0oJKCmJubs8tiOewuKfF4fIaPGIAeVFIQTDDQIwiFQrf4iAHoQSWlH+y9V2RpIpHoP8SAHlRSEOwtOBOJRFRZricQCKjJZFItl8tn+YgB6EElBWGz2QZ6BMFgcDiPYNY+cwkJ5axGHs/zEQPQg0qKGbK0sPfZdAh6UElBeK7f8MlilHRqe5GPGIAeVFIQk0ePDfQbeLC0PJzfwMkTUwNdwNPVJ//mAjwez7K+Kfv//22fPj3QBWwmkovicaVSWfqrC0ilUpfFje7fvXdOPO6V798OFsTj9mYM6EElRUfcqNVqbd25Hej7PXDx/IVT0WdrTf34xfrzfb4V9qCSopNOp/dEQfbd+7H4Ruyn2Omh9QtXnWNypwM9qKSIiBsyeZ3d4olXyc3R2MsN9VFoRf2wk1O/Fr+MrjwMTYhr19eiab5FG+hBJUVEUZR5ceM3W69/8VMGxDXbb1PGTRjQg0qKjNPpHBcFlJ1sVivvlzR2Jww95dPH3XE+2gF6UElBsNfS9IPE6/UqhUJhOB8kRC6XO+5yua6wV7RL7na7Z/kyCPSgkmKGw+E4LMotFssRfqon0INKigz76Iyxr55OotFoQrwAFD7aAXpQSZFBArM0Go06H28DPaikyCCBWer1+g8+3gZ6UEmRQQKz8NEO0INKyjCAHlT+v2gjfwDNQh1izdJWJQAAAABJRU5ErkJggg=='); -} - -.record-video { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwAAADsABataJCQAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAACEElEQVRYR+2XvUscQRiHT89vSJEgWgSDBARTJIUELBQ8LZNaLCyCmCqICKZJ5T8QBSsr4UBE7QQFIW3wE2KKgEjiB1goCFEEEfxIzucnMzIst3vnMbjNLTzs7Ozs+/7mnXc+NpHJZBJxEqtzdfxeQOIRLzfiRQHFCLgRmCAPn2fJxVfUrfkkLAkvcbIEzQERb3lmvvgjTIB18hNnHVBmhDy6AAk5gn54CrEIkIgLGIVPPsMvW7mGIDjeh3EL8JqAhUSgKCCfCPwntCeQhm5ohw8wD+eg9/d2HpqEuQT8w/gmvAwsYPbxPYXfrgjfAjYw/ibEua2uMtP6rjMPFRA1DU8xWAslOQTodSVIbN4CtBCNQdRCtML7UiNgins23L1lOF8BWoo/Qq6leNrp+R830Zxyn9NmIR8B2oxSUG4+jNoL0rSpMRFo4L4bEDHLs8ZfVxLWowQUsh1/w2CT08NWysr4K5gDDY+9XlPYjhKgA8kz5wNb1IFEyl1+8KwEVIK+MxGw7bWVfwUbQdv7zxTO4NjHqfgJhsbhBmagMYtwW6XQKzLf4RqGfAjQtJNR5YvCPQkvQkS0UL9onGvI6nwIkK9q6IV9I0LHuUFoAw1bJ3yBZeNc58oUJH0JkAjNgB44AK33f2EHtmAPNOZaqlehCyr0kU8Bsqezo6bgCASn4S/qBqBePVfjUAFx/SHH/nd8C3srt2KeTS1mAAAAAElFTkSuQmCC'); -} - -.stop-recording-audio { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAADAUlEQVRYR7WWS08TURiGhxTULSGUhZKouBILXhGMFkNCjJaiwXoJlI1FKiqlSpteglpahSqSYJsq7awhTUUaVizd+xtcuDQmxkTdeRnP15xpzhzedhoiT/IkzDvnO+9kphNG0TQNakaxWLTk8/lENptNqKraxuOqwB4UktVYXV1ds1qtmiw/XRHYg0KyEolEYgGV6w4NDbXypVuAPSgkEePj4+2oVJYv3wLsQSGJcDqdl1GhbCaTucBHDMAeFJJmyKWLi4umQ7AHhSSiq6vLJhfLsruUDgaDHXzEAOxBIYlgBTU9Ao/Hc4WPGIA9KCSrwd77tFwaCoWqDzFgDwpJBHsLjnq9XlUu13W5XGo4HFZzudwxPmIA9qCQRLS0tNT0CEZHR3fmEXTaOk6jQtkJ751uPmIA9qCQNEMuTS29Mh2CPSgkEY6Ll5xyMTIemx3kIwZgDwpJROvefTX9BtzDIzvzGzh0sK2mC7g3cff/XIDD4RjRN2X//7/a2o/UdAGRUHhQPF5ZWRne1gXEYrEz4kY3r984Lh5X8t3btV7xuLQZA/agkNQRN9rY2Ji5dtVV9Xvg1ImTh333J4v68YMp/zLfCvegkNSJx+NLYsHc02cNwenAezHTpfW95+wNcqYDe1BIiogbsvICu8XN0XCkPvBwWr3tGVOfzyfVN5nX9WO3PM3i2qlJX5xvUQL2oJAUSafT3eLGj2cefeCnDIhrZp/EjJswYA8KSRm73d4oFpDzc3NabjmrsTthyMmXLxYa+WgZ2INCEsFeS9MPkoGBgXQqldqZDxIimUwe6OvrO8teUUNxNBrV+vv7O/kyCOxBIWlGT0/PLvECmpqadvNTFYE9KCRl2EdngH31lPX5fCHxAtxudygSiQT8fn/pPHt9A3y0DOxBISkjltXq+vp6gY+XgD0oJGVQgZmFQmGTj5eAPSgkZb7X1f0oLTfxo8XySZePloE9KCRF2NH+P4rymfnrt6L8/Kso39jfX/TSSvLxMrAHhdtWUfYwz5dFawxqyj+MRz2Y+XGHbwAAAABJRU5ErkJggg=='); -} - -.stop-recording-video { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwAAADsABataJCQAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAACAElEQVRYR+2XvUscQRiHT42aBCwU0SIoQRBioUUQLBROLWMtKSxEtBKRQGys/AsUrKwC14itoCDYip+gFoJIiAoWCoKKIIJfOZ+fzBzDcbv3weA2d/DA7M7uO8+887FzsWQyGYuSSBtXx1MCsXf8uRkvChQz4GZgjnn4JcNcbOHelk+CJuEDjazAtzSJdq5ZL/4IErCN7NNYHD4YkXcXkMgFDEM1RCIgiXuYhlGf6VesbEOQPt7nUQt4nYCFZKAokEsG/pPaa0hAP3TBICzCHag+FSffSZhN4IXge9CUtoHZyz4Kf10J3wI7BG8LaNze/miW9Vtn8hUIW4Y3BKyFkiwCqq4EyeYsoI1oBsI2og3qSyXwdrjKAHXut+V3rgLaikcg21Y8b3seIjDkZGcpFwF9jLqh3LwY9i1I8MxnMwQNARnQ+OtXBtthAoV8jlcJ2Oz0sMOVMMNjq1spHIUJ6EBS4wSzRR1IZO6yy7UmoCboD5MB+3xcEk4Gbe8nKNzCpY9TcRWBZuEZFuBrBnF7S6nvgDV4gl8+BLTsFFTz5RH+QGOAxHfuL5vGNWR1PgTU1icYgFMjoePcOHSChq0HJmHdNK5zZTeU+RKQhFbATzgD7fdX8A8O4QQ05tqqN6EXKvSSTwHF09mxAabgWPEdDiiPQb16rocDBaL6hxz5v+NXmoPQBeoNXQgAAAAASUVORK5CYII='); -} - -.stop { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAAEzUlEQVRYR8VXWUhtZRS+Hud5xAk9TsccUBHRFNFMQUUCLRUjwUBxDpQjCE744AReE3FMSQ3SNBNyfOmpxx6CiKCX6EKjdIsLNyoiClbr+9n78J999j57Sxfa8HHYe69/rW+v/1vrX+cBET34PyGCW7x82M6X4c8IZARpgGcBDD8GbE0vEdsCAQQNYxQxRhkfMh4x/mSAPfA34zHjY8Y8o4YRqZA1JGKFAAK/wNiy2Wx3YWFhlJycTFlZWZSbm0t5eXkuZGdnU2pqKkVHR5O/v/8Thegr/BujZM6DiDcCNraOZ7zh4+PzNZyWl5fT+Pg4r/GumZWVFWpqaqKkpCQQuWMfa0r2sHVulxEBBM9kPAwMDPyloKCAZmZmTANrie3u7lJtbS2Fh4dji64YFdot0SMA8djBOiQk5Pf6+nq6uLi4d3CZTE9PD8XExKgknpdJ6BGAcGaCg4N/RRrN0m31/fDwsNAG+z5nZDFElWgJoITa/fz8vsd+W3Vu1a6zs5M4q39xjFlGiB6BWH74EcSD/dNzPDk5Sefn56bk1tbWdG1KSkqIq+k7jvMiwyZnAMLrZNH91tbWpru4q6uLoqKiKD8/n05PT3Vtbm9vqbKyUlTA2NiYh83CwoLwwbH2oAWZAErkg4SEBDo5OfFYCGeKmkXjycnJocvLSze76+trKi4uJl9fX2ETFxdHi4uLHr6KioqIS/tntkmRCdg5NU+N9v7s7Ew0HDhWgcajbtPNzY1oTOzY9T4zM5MODg48CAwMDBBnGnavygRa8XBwcNBwf4+OjsjhcLiRQBCkNS0tzS14RkYG7ezs6PqCn4iICPh5SyawiDa7tbXlVWCHh4eUkpLiRiI0NNTtPj09nfb39736iY2NxZpPZALHkZGRlpoO0pqYmOgWVN0WnAV6addWVHx8PNZ/KxN4H+qEkKzUdW9vr7qPLiJYv7S0ZGm9QuAHmcB7yIBW2Xpk9vb2xKknCw4ZgPqrq6vvQ+AbmcBDlBmce8vA9va2OI7lauDu5rrnLko1NTWmJFCi7ONTmcBrQUFBNDIyYrgY3Q1fLgdHPxgaGiJFVOIdH8HU2Nho6AcljWyzLWrUNRE5uA8YpnBjY0OUmhy8sLDQFWR+fp7QxNT3KOnm5mZdEqOjo4SPZdvXZQKY7x6hhV5dXek2D7XcQLSsrMzDRksCQtM7E7CWffzE8RwyAcx9TjBDz9fTQUtLC6FXeBPa7OysyATO/76+Pg8/6+vr6na9qz0LcDpmML5Eqo+Pj3VJTExMmApseXmZjOyqqqqIhfojx2nQnoYggLG6KyAg4HFdXZ1pICv9Qrbp7+9XDzTMiBh2PQYSPItmvIn97ujoeGYkpqamSGk+n7H/Uny9EQG8eI7xDvpCa2vrfybhdDpF6+bG9QX7fZkBwYtLFqH6DL8QZB7jkGfDfyoqKggN6L4pR1uHcJUB5HP2h/8IwXIgIwIqCYhyjkVzh0bT0NBAm5ubpkTQaDD/2e12nBd/sA8MotXyl5tlQH2PyTWU8RLjmok8RRmi+7W3t9P09DStrq4KzM3NUXd3N5WWlorpl4WMRvMVY5iRyMD/RY/LWwZkY+gCFVLHeJvxBM0Ihw96vwo8Uw4oDJ1OJTC20/ByEbjv/j5L+38BGxuYOLu/9/8AAAAASUVORK5CYII='); -} - -.take-snapshot { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAA8dJREFUWEftVktIW0EU1aq0BUGrYuL/WxF/UasmSm0SBbVqVCrGX0T8VFBpLSrBLxIjKkb8oAtR9xWhIAgtLXRfWorgqqtC/XTTLnTTRW2dnnnOG98zkdTfosULh7w3c+ee827u3BmXa/svbXp62rWrq+tmSkrKncbGxqTm5uZ7paWl3jExMa7M5fJtYWHBY3R09K7BYNCB6JFOp7PExsZu+vv7EwqFQjETGBioYO4Xs9XVVW98oSIxMVHZ3d1dAQJzWFjYEEjfpqam7iclJZGWlhbS09ND9Hq9IIDhPgtxdltfX88YGxurioqKmgsPD18D4UulUvkqOTn5q4SAJCQkkKmpKQJzoaivr+dzJSUlQxaLxYuFdG4TExO38aWtWVlZ70G4FRER8Q2kP2kwKYlIwEj4+OzsLIFYPhcSErKH91gW/tjm5+fd5ubmnthstscoliCkcZkuAJkA/H88CEVvby8nWVxclM2VlZUJc0tLSyQvL4+OHQK/GQ6AOEZ7bDU1NW7FxcV9mPwcHBxsQvHsNDU1cZKKigoZiThOIR2nwPrD6Ojo73jegPANfIAtLS3NaDabjZOTk36MUm61tbVuqF4qgAbYlRJQpKeny0hGRkbI+Pg4qaqqEt5BcoCC/IjnZZAtDgwMNMfFxXli+3larVYPRnO6SQVQYP+C94icVrM4LkVkZOQaauM5is4SFBTU2tfXl8HCnd3q6urcUDxcAAVNOxVAf3NzcwlqYwZF9BCFmI/9rNdoNMGoaOXKysotFub8JgpQqVT8ywMCAghSSNra2gh9Rpp/QNg+w94FoWTUR1ZdXS0UoVQAnHg2sPdJaGgof6cQ/U765ufn87nh4WG69WTrGAIZ9ZHRDKAGnjlwFGAymYTOhhbLx0QSCqkvtrBsrry8nM9JIBdQWVnpWlhYmIzKfYEtSCCGO2dnZxP832TEaiUdTzto8QnjDQ0NBE2KdHZ2cl8RarVamGtvbycatcZuHpALoIY0+6JLfUCRkczMTO6sQl+Pj48XRDyAmFNSelbYCzAajT4FBQXvHDhfBewFoNJR6MpfopNWq5X9lxeBTqtzLqCoqMgXR+eG6GQoNmCt44BnBWI7F4DBgBNOV4l/SEBOTg6y6Di1zoAbkl08hr8XIAbb+rJFtoGdrW2n2N3e4escxQSua8BeAA4jP2xDfo2+KqBNb6LH2N+McIdz7+/v16L3v3a08DxA297EDeuT+I7b0htc9XS4MbkzWrkNDg7eQEv2grPyMoBzxQe3aV/xHUe1F07VG4zu2mAuLn8AJ5n+SnkR0KgAAAAASUVORK5CYII='); -} - -.zoom-in { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAAe1JREFUWEftl8tqwkAUhn2DPoV3vEaNikENaHAruhLUbUC87FwIbly5cKGbgNBdu3GbF+kTTf2HOSVTx7SL0Aj1wE+mkzP/+RzN5DQSZjDGxCikkACi0SjLZrO+isfjvsj7/f4ln8+zTCajXE9CLeRLAJqmsWKxyIUxyft3qVTyBdjtdma5XGaFQkHygMgbSiQS/gAQimEOVxLMRboyDoeDqeu6tI7G5I8dGgwGagBKzOVyH4vFYrNarSRdt3gj0u/Ger3eLJdLaR28KpUK9x4OhyydTqsBCMJxnDcxHVgYhuH2+32+C6lU6u8BRqORC+/QAEzT5ACoEQpAq9VyqcZjAuC7wWOGx+hyuThiOrCYz+fv8IdisdgtQBjxBHgCPAEeCwAHBL2vT6dT4Cdhr9fjJyFO2uvrnleWAOgmII7HY+AAjUbDhTeUTCbVAATxP19GuIHtAcD5fA4coNls/twPAAA/xmtzGThAu93+3Q5AaKun0ymbzWZsMpnwMVSr1V5F+t0Yj8df+SR4UPG7ALT9SEAHa1kWfyS9PT7ui3Rl0P8F8KI1JJrDVQmAhSiGK4p7F5EAJtKVsd1uTW8+BA+vD8bKthxFq9Uq63a7/JOiGAlQUKfT8QVA1Ot13lXRmu+Ct23btwBhxAMAsMgnlwgSabRVBN4AAAAASUVORK5CYII='); -} - -.zoom-out { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAAglJREFUWEftV8lqAkEQzYd4EuK47ytueHA5OPgFjoIHEVzwYOIl4NWf8JKDl/xXPqPSr+nSUceZEYfEgA8Kpal686yqqWpf/gWCwSAlEgmKxWK02+3e1LEl4BsOh6W/OrofmqZRKpUiXdepXq9/qGNLpNNpgmWzWRoMBpo6vg+RSIS63a4krVQqtgKSySRlMhlvBdRqNcrn85K0XC7/vgCQ5nI5mVqnEsAX5YKAfr/vjQA0Hwjxy9wI4B7wTABn4BYB8C+VSu4FiDrrSB0eIuosDWR4nXAGUjcCuFnhz0IQZzbRyJev6Hg8lrUrFAqEpuNaMhEHu3kNO52O9OVYsyAYZoVyPwIC0OmNRkMGczbMRG4EcAO2Wq1DDMezRaPRSwGr1cq32WxoOp3SbDaztPl87jjdDMP4WiwWtFwuEfN9zgETz/pU7k888cQDYb1e+8SEMuwsFAoZyv0qxCS1jDVbr9e75JlMJofJd82wF5zuAzz97AwXHOV+BEaxlTOPT/5erVZtBZzHmj/ZLEex2ANyG55bPB4/IXCzjhGHfcCrGXFmzmKx6DjST4DUM5FbAfAX5fLmQoKa3ZIB+CEDYjE9BXgjQLy7khR1bbfbtgLQL7jYwH84HHojIBAIHDq72Ww6ZgB+EDAajbwR4Pf7pQCQbrfbd3VsCfwv5Gzt9/tXdfzAIKI/NHr5AU4kDfWD0WSsAAAAAElFTkSuQmCC'); -} - -.media-box video { - width: 100%; - vertical-align: top; - object-fit: fill; -} - -.media-box audio { - height: 5em; -} - -.volume-control .volume-slider, .media-controls .volume-slider { - width: auto; - background: rgba(255, 255, 255, 0.09)!important; - border: 1px solid white; - height: 33px; -} - -.volume-control .volume-slider input[type=range] , .media-controls .volume-slider input[type=range] { - margin-top: 9px; - height: 15px; - outline: none; -} - -input[type=range] { - -webkit-appearance: none; - -moz-appearance: none; - -o-appearance: none; - appearance: none; - background-color: rgb(83, 77, 77); - width: 200px; - height: 20px; -} - -input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - -moz-appearance: none; - -o-appearance: none; - appearance: none; - background-color: black; - opacity: 0.5; - width: 10px; - height: 26px; -} diff --git a/static/kevin-master/assets/css/getHTMLMediaElementFull.css b/static/kevin-master/assets/css/getHTMLMediaElementFull.css deleted file mode 100644 index 108668e..0000000 --- a/static/kevin-master/assets/css/getHTMLMediaElementFull.css +++ /dev/null @@ -1,160 +0,0 @@ -/* -Muaz Khan - www.MuazKhan.com -MIT License - www.WebRTC-Experiment.com/licence -Documentation - github.com/muaz-khan/WebRTC-Experiment/tree/master/getMediaElement -*/ - -.media-container, .media-container * { - margin: 0; - padding: 0; - -webkit-user-select: none; - -moz-user-select: none; - -o-user-select: none; - user-select: none; -} - -.media-container, .media-container * { - -moz-transition: all .5s ease-in-out; - -ms-transition: all .5s ease-in-out; - -o-transition: all .5s ease-in-out; - -webkit-transition: all .5s ease-in-out; - transition: all .5s ease-in-out; -} - -.media-container { - max-width: 100%; - max-height: 100%; - display: inline-block; - overflow: hidden; - vertical-align: top; - background: white; -} - -.media-box { - background: black; -} - -.media-controls, .volume-control { - margin-top: 2px; - position: absolute; - margin-left: 5px; - z-index: 100; - opacity: 0; -} - -.media-controls .control, .volume-control .control { - width: 35px; - height: 35px; - background-position: center center; - background-repeat: no-repeat; - float: left; - background-color: rgba(255, 255, 255, 0.84); -} - -.media-controls .control:first-child { - border-bottom-left-radius: 5px; -} - -.volume-control .control:first-child { - border-top-left-radius: 5px; -} - -.media-controls .control:hover, .media-controls .selected, .volume-control .control:hover { - background-color: rgba(255, 255, 255, 0.74); -} - -.media-controls .control:active, .media-container .selected, .volume-control .control:active { - background-color: rgba(255, 255, 255, 0.44)!important; -} - -.mute-audio { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAACsUlEQVRYR92Xu2siURTGp0hnJRgVGVNtEcHOiI2taWIa3Vgpgu4qiKBoCpOgxgdofD8QTFYUXMRSRLstt9xyy/0Tttxyi9kz17mXq7majFED+8EH+p2Zub+5j4NygiC8q/8PDQaDn9LHw6rf739Sq9UCthQfRk9PT2Rg7Ha7/U0q71erA2OXy+X9AgQ/B3KsgbFZADc3N25clyL5SiaTKnqgdW40Gs8A4vE4ARD9+Pj4XSq9Ts1m8xf9gE0uFosIYDwezyaTCXnjVqvVpq+T4oWur6/5UChEiuFweOkinL/GeAnoDD0ENJ1Of7ByTqFQ8HQB+/7+vi3WWbV1fnh4eAYgWsxEQb8gWSQS+YjCk5MTJkA2m5UNUK1WyR4olUq/cW6z2cJidn5+foSz09PTBYBer2cCpNNp2QC1Wm1pE9I1WIIz8BGAoe+xWEwYjUY8p9PpmAB3d3dbLwEWvOUHXHO73WdiZjAYrDiDE8JzWq2WCZBKpWQDwNstAXg8HgJgtVoRgN1uJwAul2v9DGwDsDoD0D8IALw5AnA6nQTg8vKS5zQazc72QKVSWQIIBAIEwGw2IwCHw0EALi4ueE6lUjEB8vn8m2fAYrEQgKurKwRgMpkIgN/v58UBmAC5XE42wOopgGeQGswOAlAqlQggGAwKnU6H546Pj5kA8DZvApjP56QPGI1G1Aeg65I+AHtv0QfWnQLo67IBYNkQQK/Xm9H5bDZDANBzCACs/wIApoIJgIogVm2dWa0Yms1X9CAQnUvRy6JvesmFQoEsgfhd+ohEXxeNRstS/DrRN29yt9td2oRY9DVer1fe7wEsn89npx/Ecr1e3wiQSCT+StH2ogdcdSaTYQLsXMPh8A8LgPWTbG+CM29cBZBKh9Xt7e0XOPfvM/hOxPrHekgzw8NZ4P4BtGizy4jmqy8AAAAASUVORK5CYII='); -} - -.unmute-audio { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAACY0lEQVRYR9WXS2/aQBDHfa9POaDGhKTpgTNIfICohfI4wC0HDuWdOCWQBKy24hmUBqduAjgVhx4Q50oIPk0/TQ/urhlbNplFEcWu+pd+EjszO7OyZweZ0zTtn4Ia3QQ1uslWNJ1OVVmWtU6n8xpM7ikSiVQ8Ho9mAGbnlcvlDq2FXT1AvV7/jRWnQIgzGg2GC6yoFQjdvsJv3ipYwVUgfHuKRt4dYYVYwLbnKxaL7WCJsu8zvHzbF8ST0ye+dUDa56vdbqOJvLsCrw5HwtXFJepnAWl1kdkgEU5gaUpRlGPCjb4gwwNNdHjwir9XvgnV8wrqZ6EnJQoGgynDlkgkjsDMpVKpgGEPBAIZTpIkWwID+gS+yndC+ewD6mcBdWhe8wCUeDzuTSaTL6y2QqGQ4brdrmmw4vPu8cOHgXBRqaJ+FlBfV7lclrAYSj6fX76CRqOBBhz49vnv6qNQu7xC/Sz0pBaRofVjNUYUxZ/g5rher2dzGuzv+XgyeDbuAavWxjSbTZvTgB6ANmGlfI76WUBaU1gMBdwc12q10ADh5S5/15eFs1MR9bOAtLpI99t6oFarmb+j0eiyB1gHoE04uH/YuAnT6bTtFhSLRS9pStstIFcywxxE9Ak8jtSNB1E4HDYPUCqVzDlQrVbNORAKhTLMJ0B74G9vwWKxkAhPJuF8Pj8mLF9BNpvdIdiSfP74SbvudPnbmy/O/xes02w2E/r9PlqIBWzdrsjgKGHFMGCLM8IKrgKhzmkymfzCChtAmPNi3R5wuyNyp6PW4n6/3/0PE6rxeKwSYrD8z4R9MLqHxv0BTZnWtpv+sYEAAAAASUVORK5CYII='); -} - -.mute-video { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwQAADsEBuJFr7QAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAABoElEQVRYR2NgGAWDNARSge4qJxL7UN0PfHx8O5iZmW8CDSYGd1HdAXJycns4ODjuAQ3Ghz8D5f8D8SKqO0BfXz+Ll5e3FmgwPnyelg7gADqAE2gBPryEZg4gMkgXUtsBTEAD2UjAi6EOAIUEsj5GZA8A0xOTpKQkNnOZ0T0qCRRIJAEfhTrgGJoeQTQHSAMdgM1cY3QH2AAFXpOAf0AdAKKR9WmCDO7q6hIPCgrSEhISShQREcFmbg26AxyhBoKyFiVYF2RwW1tbrr+//zEWFpZrQIzNvDaaOsDGxqZdWVn5GyMj408cHqKNA9jY2EqApWg4Dw/PZk5OTnwhSTMHnGZiYjoA9PVjAlFJGweA4hsY7MSkIdo4gIQEPOqAYRoCwBxATAIEqaFNCADLgcdAR9wFWvBhQLIhOzt7K7AgygE6Yi+B0KBNCAAttQA6gNfAwGASsCqmf0kIDHZwZZSTk1Po4OBwBlgw3SK2MiK1OsZVdcOqYwNgdRzOzc3dyM/PT1R1rAJ0eB8VMKhhAwfAaNAANkiwmeuNXh2P8kdmCAAAkSPyEJegDaEAAAAASUVORK5CYII='); -} - -.unmute-video { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwQAADsEBuJFr7QAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAACFUlEQVRYR2NgGIFgPtDPGQPlb5Dl/4H4PRBL4HNEKlCynEjsQ6RvYJZ/B6p3wKuHj49vBzMz802gImJwFxEOaID6HGS5B0H1cnJyezg4OO4BFeLDn6GGLiJgIGmWgwzT19fP4uXlrQUy8eHzRDigAKoGFO8RBH0OUwB0AAfQAZxAPj68hIADEpAsB7GpDhbicQCy5RXE2swEVMhGAl4MdQAoJJD1JSL5vAGYnpgkJSWxmcuM7jBJoABIM7H4KNSiY0h6+oDsH1DxBpAFQAdIAx2AzUxjdAfYAAVek4BhFoFokL6PQPwPZnlXV5d4UFCQlpCQUKKIiAg2c2vQHeCIFHSgVEsungMyuK2tLdff3/8YCwvLNSDGZlYbrRygCzLYxsamXVlZ+RsjI+NPHJ6hjQPY2NhKgKVoOA8Pz2ZOTk58oUgzB5xmYmI6APT1YwLRSBsHgOIbGOzEpB/aOICExDvqgGEaAsAcQEwCBKmhTQgAy4HHQEfcBVrwYUCyITs7eyuwIMoBOmIvgdCgTQgALbUAOoDXwMBgErAmpH9JCAx2cF2Qk5NT6ODgcAZYMN0itjKCVceglivI5aCqFdR+J6WKBqnVBDkAWB0bAKvjcG5u7kZ+fn6iqmMVoL4rUMt/A2lQiwfUwCAVgxo2cACMBg1ggwSbGd7o1fF0qOXEtd3RdVPIbxixloMCDpZViO84UBjcyNoBhLMZ3JbarLEAAAAASUVORK5CYII='); -} - -.record-audio { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAACuUlEQVRYR72WTW8SURiFm9jquiGFhXahdWWl9bMWozQhIUaBahA/0spGKli1VC0EaqpSUIpWksoELcwaQrBCWLl073/xN4z3JXfIncuBIUZ8krOYM/e9z2SGCTOiaRqMGc1m81CtVsuUSqWMqqpTvO4L9KCS0o9qtXpgtVo1Ofx0T6AHlZReZDKZXSTX4/f7J/nSLqAHlRREOByeRlI5fHkX0INKCsLn891EQjnFYvEaHzEAPaikmCFL8/m86RD0oJKCmJubs8tiOewuKfF4fIaPGIAeVFIQTDDQIwiFQrf4iAHoQSWlH+y9V2RpIpHoP8SAHlRSEOwtOBOJRFRZricQCKjJZFItl8tn+YgB6EElBWGz2QZ6BMFgcDiPYNY+cwkJ5axGHs/zEQPQg0qKGbK0sPfZdAh6UElBeK7f8MlilHRqe5GPGIAeVFIQk0ePDfQbeLC0PJzfwMkTUwNdwNPVJ//mAjwez7K+Kfv//22fPj3QBWwmkovicaVSWfqrC0ilUpfFje7fvXdOPO6V798OFsTj9mYM6EElRUfcqNVqbd25Hej7PXDx/IVT0WdrTf34xfrzfb4V9qCSopNOp/dEQfbd+7H4Ruyn2Omh9QtXnWNypwM9qKSIiBsyeZ3d4olXyc3R2MsN9VFoRf2wk1O/Fr+MrjwMTYhr19eiab5FG+hBJUVEUZR5ceM3W69/8VMGxDXbb1PGTRjQg0qKjNPpHBcFlJ1sVivvlzR2Jww95dPH3XE+2gF6UElBsNfS9IPE6/UqhUJhOB8kRC6XO+5yua6wV7RL7na7Z/kyCPSgkmKGw+E4LMotFssRfqon0INKigz76Iyxr55OotFoQrwAFD7aAXpQSZFBArM0Go06H28DPaikyCCBWer1+g8+3gZ6UEmRQQKz8NEO0INKyjCAHlT+v2gjfwDNQh1izdJWJQAAAABJRU5ErkJggg=='); -} - -.record-video { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwAAADsABataJCQAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAACEElEQVRYR+2XvUscQRiHT89vSJEgWgSDBARTJIUELBQ8LZNaLCyCmCqICKZJ5T8QBSsr4UBE7QQFIW3wE2KKgEjiB1goCFEEEfxIzucnMzIst3vnMbjNLTzs7Ozs+/7mnXc+NpHJZBJxEqtzdfxeQOIRLzfiRQHFCLgRmCAPn2fJxVfUrfkkLAkvcbIEzQERb3lmvvgjTIB18hNnHVBmhDy6AAk5gn54CrEIkIgLGIVPPsMvW7mGIDjeh3EL8JqAhUSgKCCfCPwntCeQhm5ohw8wD+eg9/d2HpqEuQT8w/gmvAwsYPbxPYXfrgjfAjYw/ibEua2uMtP6rjMPFRA1DU8xWAslOQTodSVIbN4CtBCNQdRCtML7UiNgins23L1lOF8BWoo/Qq6leNrp+R830Zxyn9NmIR8B2oxSUG4+jNoL0rSpMRFo4L4bEDHLs8ZfVxLWowQUsh1/w2CT08NWysr4K5gDDY+9XlPYjhKgA8kz5wNb1IFEyl1+8KwEVIK+MxGw7bWVfwUbQdv7zxTO4NjHqfgJhsbhBmagMYtwW6XQKzLf4RqGfAjQtJNR5YvCPQkvQkS0UL9onGvI6nwIkK9q6IV9I0LHuUFoAw1bJ3yBZeNc58oUJH0JkAjNgB44AK33f2EHtmAPNOZaqlehCyr0kU8Bsqezo6bgCASn4S/qBqBePVfjUAFx/SHH/nd8C3srt2KeTS1mAAAAAElFTkSuQmCC'); -} - -.stop-recording-audio { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAADAUlEQVRYR7WWS08TURiGhxTULSGUhZKouBILXhGMFkNCjJaiwXoJlI1FKiqlSpteglpahSqSYJsq7awhTUUaVizd+xtcuDQmxkTdeRnP15xpzhzedhoiT/IkzDvnO+9kphNG0TQNakaxWLTk8/lENptNqKraxuOqwB4UktVYXV1ds1qtmiw/XRHYg0KyEolEYgGV6w4NDbXypVuAPSgkEePj4+2oVJYv3wLsQSGJcDqdl1GhbCaTucBHDMAeFJJmyKWLi4umQ7AHhSSiq6vLJhfLsruUDgaDHXzEAOxBIYlgBTU9Ao/Hc4WPGIA9KCSrwd77tFwaCoWqDzFgDwpJBHsLjnq9XlUu13W5XGo4HFZzudwxPmIA9qCQRLS0tNT0CEZHR3fmEXTaOk6jQtkJ751uPmIA9qCQNEMuTS29Mh2CPSgkEY6Ll5xyMTIemx3kIwZgDwpJROvefTX9BtzDIzvzGzh0sK2mC7g3cff/XIDD4RjRN2X//7/a2o/UdAGRUHhQPF5ZWRne1gXEYrEz4kY3r984Lh5X8t3btV7xuLQZA/agkNQRN9rY2Ji5dtVV9Xvg1ImTh333J4v68YMp/zLfCvegkNSJx+NLYsHc02cNwenAezHTpfW95+wNcqYDe1BIiogbsvICu8XN0XCkPvBwWr3tGVOfzyfVN5nX9WO3PM3i2qlJX5xvUQL2oJAUSafT3eLGj2cefeCnDIhrZp/EjJswYA8KSRm73d4oFpDzc3NabjmrsTthyMmXLxYa+WgZ2INCEsFeS9MPkoGBgXQqldqZDxIimUwe6OvrO8teUUNxNBrV+vv7O/kyCOxBIWlGT0/PLvECmpqadvNTFYE9KCRl2EdngH31lPX5fCHxAtxudygSiQT8fn/pPHt9A3y0DOxBISkjltXq+vp6gY+XgD0oJGVQgZmFQmGTj5eAPSgkZb7X1f0oLTfxo8XySZePloE9KCRF2NH+P4rymfnrt6L8/Kso39jfX/TSSvLxMrAHhdtWUfYwz5dFawxqyj+MRz2Y+XGHbwAAAABJRU5ErkJggg=='); -} - -.stop-recording-video { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwAAADsABataJCQAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAACAElEQVRYR+2XvUscQRiHT42aBCwU0SIoQRBioUUQLBROLWMtKSxEtBKRQGys/AsUrKwC14itoCDYip+gFoJIiAoWCoKKIIJfOZ+fzBzDcbv3weA2d/DA7M7uO8+887FzsWQyGYuSSBtXx1MCsXf8uRkvChQz4GZgjnn4JcNcbOHelk+CJuEDjazAtzSJdq5ZL/4IErCN7NNYHD4YkXcXkMgFDEM1RCIgiXuYhlGf6VesbEOQPt7nUQt4nYCFZKAokEsG/pPaa0hAP3TBICzCHag+FSffSZhN4IXge9CUtoHZyz4Kf10J3wI7BG8LaNze/miW9Vtn8hUIW4Y3BKyFkiwCqq4EyeYsoI1oBsI2og3qSyXwdrjKAHXut+V3rgLaikcg21Y8b3seIjDkZGcpFwF9jLqh3LwY9i1I8MxnMwQNARnQ+OtXBtthAoV8jlcJ2Oz0sMOVMMNjq1spHIUJ6EBS4wSzRR1IZO6yy7UmoCboD5MB+3xcEk4Gbe8nKNzCpY9TcRWBZuEZFuBrBnF7S6nvgDV4gl8+BLTsFFTz5RH+QGOAxHfuL5vGNWR1PgTU1icYgFMjoePcOHSChq0HJmHdNK5zZTeU+RKQhFbATzgD7fdX8A8O4QQ05tqqN6EXKvSSTwHF09mxAabgWPEdDiiPQb16rocDBaL6hxz5v+NXmoPQBeoNXQgAAAAASUVORK5CYII='); -} - -.stop { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAAEzUlEQVRYR8VXWUhtZRS+Hud5xAk9TsccUBHRFNFMQUUCLRUjwUBxDpQjCE744AReE3FMSQ3SNBNyfOmpxx6CiKCX6EKjdIsLNyoiClbr+9n78J999j57Sxfa8HHYe69/rW+v/1vrX+cBET34PyGCW7x82M6X4c8IZARpgGcBDD8GbE0vEdsCAQQNYxQxRhkfMh4x/mSAPfA34zHjY8Y8o4YRqZA1JGKFAAK/wNiy2Wx3YWFhlJycTFlZWZSbm0t5eXkuZGdnU2pqKkVHR5O/v/8Thegr/BujZM6DiDcCNraOZ7zh4+PzNZyWl5fT+Pg4r/GumZWVFWpqaqKkpCQQuWMfa0r2sHVulxEBBM9kPAwMDPyloKCAZmZmTANrie3u7lJtbS2Fh4dji64YFdot0SMA8djBOiQk5Pf6+nq6uLi4d3CZTE9PD8XExKgknpdJ6BGAcGaCg4N/RRrN0m31/fDwsNAG+z5nZDFElWgJoITa/fz8vsd+W3Vu1a6zs5M4q39xjFlGiB6BWH74EcSD/dNzPDk5Sefn56bk1tbWdG1KSkqIq+k7jvMiwyZnAMLrZNH91tbWpru4q6uLoqKiKD8/n05PT3Vtbm9vqbKyUlTA2NiYh83CwoLwwbH2oAWZAErkg4SEBDo5OfFYCGeKmkXjycnJocvLSze76+trKi4uJl9fX2ETFxdHi4uLHr6KioqIS/tntkmRCdg5NU+N9v7s7Ew0HDhWgcajbtPNzY1oTOzY9T4zM5MODg48CAwMDBBnGnavygRa8XBwcNBwf4+OjsjhcLiRQBCkNS0tzS14RkYG7ezs6PqCn4iICPh5SyawiDa7tbXlVWCHh4eUkpLiRiI0NNTtPj09nfb39736iY2NxZpPZALHkZGRlpoO0pqYmOgWVN0WnAV6addWVHx8PNZ/KxN4H+qEkKzUdW9vr7qPLiJYv7S0ZGm9QuAHmcB7yIBW2Xpk9vb2xKknCw4ZgPqrq6vvQ+AbmcBDlBmce8vA9va2OI7lauDu5rrnLko1NTWmJFCi7ONTmcBrQUFBNDIyYrgY3Q1fLgdHPxgaGiJFVOIdH8HU2Nho6AcljWyzLWrUNRE5uA8YpnBjY0OUmhy8sLDQFWR+fp7QxNT3KOnm5mZdEqOjo4SPZdvXZQKY7x6hhV5dXek2D7XcQLSsrMzDRksCQtM7E7CWffzE8RwyAcx9TjBDz9fTQUtLC6FXeBPa7OysyATO/76+Pg8/6+vr6na9qz0LcDpmML5Eqo+Pj3VJTExMmApseXmZjOyqqqqIhfojx2nQnoYggLG6KyAg4HFdXZ1pICv9Qrbp7+9XDzTMiBh2PQYSPItmvIn97ujoeGYkpqamSGk+n7H/Uny9EQG8eI7xDvpCa2vrfybhdDpF6+bG9QX7fZkBwYtLFqH6DL8QZB7jkGfDfyoqKggN6L4pR1uHcJUB5HP2h/8IwXIgIwIqCYhyjkVzh0bT0NBAm5ubpkTQaDD/2e12nBd/sA8MotXyl5tlQH2PyTWU8RLjmok8RRmi+7W3t9P09DStrq4KzM3NUXd3N5WWlorpl4WMRvMVY5iRyMD/RY/LWwZkY+gCFVLHeJvxBM0Ihw96vwo8Uw4oDJ1OJTC20/ByEbjv/j5L+38BGxuYOLu/9/8AAAAASUVORK5CYII='); -} - -.take-snapshot { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAA8dJREFUWEftVktIW0EU1aq0BUGrYuL/WxF/UasmSm0SBbVqVCrGX0T8VFBpLSrBLxIjKkb8oAtR9xWhIAgtLXRfWorgqqtC/XTTLnTTRW2dnnnOG98zkdTfosULh7w3c+ee827u3BmXa/svbXp62rWrq+tmSkrKncbGxqTm5uZ7paWl3jExMa7M5fJtYWHBY3R09K7BYNCB6JFOp7PExsZu+vv7EwqFQjETGBioYO4Xs9XVVW98oSIxMVHZ3d1dAQJzWFjYEEjfpqam7iclJZGWlhbS09ND9Hq9IIDhPgtxdltfX88YGxurioqKmgsPD18D4UulUvkqOTn5q4SAJCQkkKmpKQJzoaivr+dzJSUlQxaLxYuFdG4TExO38aWtWVlZ70G4FRER8Q2kP2kwKYlIwEj4+OzsLIFYPhcSErKH91gW/tjm5+fd5ubmnthstscoliCkcZkuAJkA/H88CEVvby8nWVxclM2VlZUJc0tLSyQvL4+OHQK/GQ6AOEZ7bDU1NW7FxcV9mPwcHBxsQvHsNDU1cZKKigoZiThOIR2nwPrD6Ojo73jegPANfIAtLS3NaDabjZOTk36MUm61tbVuqF4qgAbYlRJQpKeny0hGRkbI+Pg4qaqqEt5BcoCC/IjnZZAtDgwMNMfFxXli+3larVYPRnO6SQVQYP+C94icVrM4LkVkZOQaauM5is4SFBTU2tfXl8HCnd3q6urcUDxcAAVNOxVAf3NzcwlqYwZF9BCFmI/9rNdoNMGoaOXKysotFub8JgpQqVT8ywMCAghSSNra2gh9Rpp/QNg+w94FoWTUR1ZdXS0UoVQAnHg2sPdJaGgof6cQ/U765ufn87nh4WG69WTrGAIZ9ZHRDKAGnjlwFGAymYTOhhbLx0QSCqkvtrBsrry8nM9JIBdQWVnpWlhYmIzKfYEtSCCGO2dnZxP832TEaiUdTzto8QnjDQ0NBE2KdHZ2cl8RarVamGtvbycatcZuHpALoIY0+6JLfUCRkczMTO6sQl+Pj48XRDyAmFNSelbYCzAajT4FBQXvHDhfBewFoNJR6MpfopNWq5X9lxeBTqtzLqCoqMgXR+eG6GQoNmCt44BnBWI7F4DBgBNOV4l/SEBOTg6y6Di1zoAbkl08hr8XIAbb+rJFtoGdrW2n2N3e4escxQSua8BeAA4jP2xDfo2+KqBNb6LH2N+McIdz7+/v16L3v3a08DxA297EDeuT+I7b0htc9XS4MbkzWrkNDg7eQEv2grPyMoBzxQe3aV/xHUe1F07VG4zu2mAuLn8AJ5n+SnkR0KgAAAAASUVORK5CYII='); -} - -.zoom-in { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAAe1JREFUWEftl8tqwkAUhn2DPoV3vEaNikENaHAruhLUbUC87FwIbly5cKGbgNBdu3GbF+kTTf2HOSVTx7SL0Aj1wE+mkzP/+RzN5DQSZjDGxCikkACi0SjLZrO+isfjvsj7/f4ln8+zTCajXE9CLeRLAJqmsWKxyIUxyft3qVTyBdjtdma5XGaFQkHygMgbSiQS/gAQimEOVxLMRboyDoeDqeu6tI7G5I8dGgwGagBKzOVyH4vFYrNarSRdt3gj0u/Ger3eLJdLaR28KpUK9x4OhyydTqsBCMJxnDcxHVgYhuH2+32+C6lU6u8BRqORC+/QAEzT5ACoEQpAq9VyqcZjAuC7wWOGx+hyuThiOrCYz+fv8IdisdgtQBjxBHgCPAEeCwAHBL2vT6dT4Cdhr9fjJyFO2uvrnleWAOgmII7HY+AAjUbDhTeUTCbVAATxP19GuIHtAcD5fA4coNls/twPAAA/xmtzGThAu93+3Q5AaKun0ymbzWZsMpnwMVSr1V5F+t0Yj8df+SR4UPG7ALT9SEAHa1kWfyS9PT7ui3Rl0P8F8KI1JJrDVQmAhSiGK4p7F5EAJtKVsd1uTW8+BA+vD8bKthxFq9Uq63a7/JOiGAlQUKfT8QVA1Ot13lXRmu+Ct23btwBhxAMAsMgnlwgSabRVBN4AAAAASUVORK5CYII='); -} - -.zoom-out { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAAglJREFUWEftV8lqAkEQzYd4EuK47ytueHA5OPgFjoIHEVzwYOIl4NWf8JKDl/xXPqPSr+nSUceZEYfEgA8Kpal686yqqWpf/gWCwSAlEgmKxWK02+3e1LEl4BsOh6W/OrofmqZRKpUiXdepXq9/qGNLpNNpgmWzWRoMBpo6vg+RSIS63a4krVQqtgKSySRlMhlvBdRqNcrn85K0XC7/vgCQ5nI5mVqnEsAX5YKAfr/vjQA0Hwjxy9wI4B7wTABn4BYB8C+VSu4FiDrrSB0eIuosDWR4nXAGUjcCuFnhz0IQZzbRyJev6Hg8lrUrFAqEpuNaMhEHu3kNO52O9OVYsyAYZoVyPwIC0OmNRkMGczbMRG4EcAO2Wq1DDMezRaPRSwGr1cq32WxoOp3SbDaztPl87jjdDMP4WiwWtFwuEfN9zgETz/pU7k888cQDYb1e+8SEMuwsFAoZyv0qxCS1jDVbr9e75JlMJofJd82wF5zuAzz97AwXHOV+BEaxlTOPT/5erVZtBZzHmj/ZLEex2ANyG55bPB4/IXCzjhGHfcCrGXFmzmKx6DjST4DUM5FbAfAX5fLmQoKa3ZIB+CEDYjE9BXgjQLy7khR1bbfbtgLQL7jYwH84HHojIBAIHDq72Ww6ZgB+EDAajbwR4Pf7pQCQbrfbd3VsCfwv5Gzt9/tXdfzAIKI/NHr5AU4kDfWD0WSsAAAAAElFTkSuQmCC'); -} - -.media-box video { - width: 100%; - vertical-align: top; - object-fit: fill; -} - -.media-box audio { - height: 5em; -} - -.volume-control .volume-slider, .media-controls .volume-slider { - width: auto; - background: rgba(255, 255, 255, 0.09)!important; - border: 1px solid white; - height: 33px; -} - -.volume-control .volume-slider input[type=range] , .media-controls .volume-slider input[type=range] { - margin-top: 9px; - height: 15px; - outline: none; -} - -input[type=range] { - -webkit-appearance: none; - -moz-appearance: none; - -o-appearance: none; - appearance: none; - background-color: rgb(83, 77, 77); - width: 200px; - height: 20px; -} - -input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - -moz-appearance: none; - -o-appearance: none; - appearance: none; - background-color: black; - opacity: 0.5; - width: 10px; - height: 26px; -} diff --git a/static/kevin-master/assets/css/stylesheet.css b/static/kevin-master/assets/css/stylesheet.css deleted file mode 100644 index 3b2f07b..0000000 --- a/static/kevin-master/assets/css/stylesheet.css +++ /dev/null @@ -1,248 +0,0 @@ -/* Fonts Copyright (C) 2011-2017 Hoefler & Co.*/ -@font-face { - font-family: "Whitney SSm A"; - src: url(data:application/x-font-woff2;base64,d09GMgABAAAAAD/gABIAAAAAnJgAAD99AAFNDgAAAAAAAAAAAAAAAAAAAAAAAAAAGh4bwXAcgQAGYACINAgsCYJhEQwKgb98galYEggBNgIkA4VoC4J4AAQgBZZ2B4RpDIFmG8GOF9g2jR5edwKpmdX3P+IoKlkvMTtQw8YRMGbZavb///cFKjLWDW7ac1BBBQZlznQWDYVyaEXnvA556nBJFlHeJNXo+Ohb3UaxbqVkVxpOB5dcj6ZdKEbIBaOVmhTLlc4N7L4aBLRELtbcwG6/YblvnkqlIWzMAH4B/61LdIhh3F+I4T3oAtuGt5KTaa8Pb1e+PyeuPHugHEFVUpFVevD//zare59oySuhoCBBOhAjnaLNDumMWY8JIybyO4cVz5r8KZ8rA7TNzigUo0iVSgFBLJRuFVAJxcKu1W+60GV91iJLVy7b/faLFExdmLb/JAVwlI9hm17Ep/E8/DF4z73vh1YkfYqi6kUEUAbQWgc4kWnTxB6U276khVaNxigipuyvNBG8BcB+ut4044X3JE+QvaGjLtgd7k/RjCTb84l9xCG73W1DxNUhTNNV0JK5TlU+u29qRbPifiIGZNBNj2ffjutWs5pNnFXEQsEXwkhqFMzt02AOMZgHJkO3tGwK1wAKFCB9v+mE60O2O6E6Dw06V+a6SMYUHmHOqV9Xb/Cruf+vJwM9k5tL/BjyYYlAGCAJAJKE3eqcyearVQhuJToC/UyWc3JoAwk0dGo/0U1blo4ei1JVcM8haJ+51NoyLFgerZx7z+T/1+lXOe9J0bc8GM/MEnzQItVxFgBKoHK3ku6T/GQ9KXGkOAbZwYHAJzvJp/w/42c5/grtOc4SoTPA3C1BjUWHFWC5RZUpur9Nt01L0FHRFNuUU265/peaZfpeY8hFz55BQz40NtMqiJyLFeXg7x4CbAAkrzGzBiDX4JznOcoTM7NVQ3OGRxkbKYgUKzrjMwWRtBtWkfTmbznLIM6zpZRSBgkiIQQJ4u5vsJzVgUDiFSyG6No9nvez33JwEYmRlCPuoYK3zy1jWr+Hd7t22tbJlgAJglablnmp/XWtshZHCCJOeXw3g+1VbgsEQBNzb5uC0MeM/cdwwQDqVovif+6CxgJEvvpUSx2ApAiA/5PrVeC4yDNvNjcAka8811QHxEM8DLAfExzqXoiFLI3b8gEQs/hfbopifFIGCDczEfG8x09lvubHoRGMw2LIn//m/wKB5FLyEgiQwaW9eUA4ogvIIVvszCZ7Q1OdsOZQVIhDWH7d+tiYEUeb3byRrFJ85aaFVBOZSYheSDgHaSItA068RqjPB0jQzEB0dLq1tpNwdw0uuQaVHDTiN0AiY5+mPW3EHQQuEhe52mRHLC9LlIR8StoTimaxyAGiviuMVGCtsXgPOjZSoYXaqwzud2BzAnnNhKav+ebnYGyyIpEG6SQTouLn/OQ3EqNx5iAkPScLkEeujKlS/eyR1GwgmVx9pZkPAYTlqEIsHH+6sV70OBcTiyjD1A5ElWEhVYM1yt7coVLD5FGp5ZDo+8UhPzjBUD6vYsPhQcfdvdHIsyAiHixKS/qBTy7/6dcH5TcsaeCg/pKBFI8x5x9iwsFTMBiWng5zcoKerjr0IJYDjwHqnyPeGTC6Gk6RKEysgHLKZNpFetmFRxPKjidXeoBDJYj8wVulqoQiaV4iuPfBFcJy6GcnkkUqAQoJqa9MN+5MZI9WczR6BxkyJpHmfa251GsQRLAuxORhaWZSRSAHQlhY4c0pamX4yZX1K7l/p/6UNhu8odEd2/LOwbp/an80V7CSGUsQkSfa1UhuG4dOAC6pKGJpPXIrnXs0yT0PmbtREmpWUheZpayc3em69cE4Dn4R3/2Z+sd0OG9GTEUlAna+NA+ljsjTec6vjegG0fcB2L+U9CmiiH9FsltOIVDRATQVE2ITE2z0p8dOSu5Q0SThblR7MSzqlVTJR750x7Cgi6oIcASF4CcMxfmxfWse2GNZuNdR91xYLNAYSiiOSWLOyCTU/b4XqdEQaQnO5FPtSPPdo6CrQNXrHliUs5yUNq8U4e7q1xKiB4IL1AyF3TafKAb35eZAp+iskWv+mymHVB+18+6hGeuAyLPYoRxc2ibwNRovLfAwP59vNC1+Cgco1uk62pCxRK11w3yF5Xtb9zwVEsvfl6WjZUdqib9HZwYUA8RqpJQqtAtO5M6+JwybgL8ZKsqQ6y4hdgSFXJshwNI8il5QzCNLlqOExMtzi4PgMnhAsU7T3QYfDV2pj4PTSQoroStyWinsJ2Vm84MDvov77c1LlCsx2LjMWVx+EWdInMOz3q87tcB4Prk2L/5Ao3r12jU+99hBUesZzmFJPqhnbzby2wjIXM1dh1xbtBUZvsXT+VB0TwVQv1JVhne6C6jbkQfVwe+q4cPy9WAFcq0kKlHlcfrkyj2Mg15HEayzGfNfis2bSEDXkVBfAgym2STEpyLQUrLSVr1cabulW+kHgMkTApRyeuuQQFTuRZfKvfBRL/hW5w1kuDgPk49u3BcKEYEyVQlx98+71Y2emqZ+YQqxKat8JW4UCJQ+EB+82GMR2EC8Q9p6oDpnSsd3VPWzOGtbvWDh/AacCmjkaOP63MoRk+7e68M5o6rZzHOcZTIZ1ccXPhF8J7mHZgY3QO+5z4C4p8prySrpMXNI6znExu3oRRyb0AkZxklp68jKtWV0yY27Lz1gaSc5+rVg0NdBNVSqutSvBs0gk7iFPYvvxL0cP5ZSoF99LI9ISKZqDybSdVhHOsOwabvVLRRonJm4tsXRjb76hWpE7WEpEcH3WTU+cN9WxX9qWntVZ0oxQrmxhVjhc1J7ykDdWYyg+wy1+1p/R0WvvdTux9zicDcbXpoDocHwHLwBrEh1xLq2TCBWNbx9gnmWbVJosOQ7FwFo+mgujDiRbe2gfxj5rlE0w/L4AiGHgYmFjYOLZyVXGfjEpAQMGDMHWLAEmDNnTUzOjSdvPkPRlS+0Z/rmZmyQkZFEwh5I8TPnAkzwFQEpQQRAT0HDcSH5QFMHoOR0s6jqdtSnz4492l9xAM2UGUJ6hg4AwKQL4BLisiBhhoODUw0RAAUAmK0DlNB5VV71SBinTVuEhUVEikFODwMjryNm4eOxZMuew2bEpu6JZHS9NJoRh4S4cpTUs/YARLQjiSRnoKegYR2DA352fQnlLLgOC9cZMwF/XRHgkqEBuiiOIgagQkOWxfgSSnLWNK3mRp8HT2a8haCJoMUVyyhTqjpZavTQm2pShmHzSqyyR6UfHNDIj4IABKIQQF2P118dInC0+Oe7J++8w2QBqn9t8ANisF2fNh1dDPDLDgudQFkU07Zy/ArdJ1JBWD/tEGAC35L8KU0Ld4hdqCkA0vdXWcgucT0AgN6KCUDNTA/HXi8BwDYA1LKOAUCjgLp2FCMAUDiU8aCY4oD/le7WQ9kyNH3WHDjzFkBOq1ipRi3adOr1nX2OOOmsi6544KyL3sJ7DMEAXeKSEEhgQQQbYqihhxFWMiKKJLIoYkl+CmNPSVzxpjo1qUtDmtKSznSnN5P+0CJ6pNc3DayYumL6iteoeBQclYzCoAiobNTvCWZyskDTY8iBMze+ZFT0nLxatOnQ7Vv7HHTcWRdcdsMT5132Hr4gKL22ydfjJqutJt4jtuGPCryHK/by7b9CxVFMecvwK9SvpCgrLSkhLioiLCTAz8fryqVzp44c2LdjxbIliyktcPpIKY9WPZEIcDsA4N9/eFwB/4b48EIVC/59wWYxGePPU4R/71TAvxCAv9//p/wtf8mfhPef+hvP8FT3u/Z8zncR/56oTJ+ZbU+pJzyyEJoCuojHwnM41xjJoUeNGSfgcL2BiNOtxaRcnzXNk5zXnU+aos/37ofNMGIiYDxdsAWsYuZzta9SktMOBpqDAvQTRdIeQbgpBcPByX9NCg5FKP7HPun1B8MRjSfTGZqdI2osLC7R8srq2vrG5tb2zu7efo44C7A7zknnAs5nsrJzeLl5fIFQJAaAAFKyi4DisgoAsp/0AEDJa02Nza0tbR1dnd09fb39A1P//P77/x8AgISrGuB7Ndf1v1h1gPslAAAiAQAQcxdo/8QOAAAQe+8HIP1xxfCIQqnVqdQA49+Bg7+aAZD0/XcgUxEAAAqfB8peqames0h2bslSyfmVy4WAzYdYtXQ0IVfhCuUyZU8K0K4PrhnUOxy52L+BpoY2FLboN8/W4eSMv7VodYCzRIA0IvdRoIsOQgNSWEBp1IDim52vjUIz7HIPzYbelzsY/qYFmzzCwQMCmP1HbW7xjAXLnuUPs5GA0RCZWqiSNH0ri1+tu40//W9Om588Stj4rceVmmFBLWMmhy/dFL7km7GZQDRPM4XfJ24okilB0baqbe65udAdALZwM9FfM67kB2dhwjbtfPlSOwQmcYJ+ULzrvQFDqjkgrWykrmqfsuzz67cKNG2+904zZhNAAEFEdOZkAwBXACDvA/ADAK2PgPk1gNoB5EWA1S+gBAAAFIIjcMzILEweNp1VjiRynyGtbdSks+BaAiFCMMVMIgLtnHv3EFVilevYhkHpXH7VKcRoE4zSVRtVVW1AlHzZDUQZGu/aHoHT19EBa6jVWu8EEZYa8t3UbTRyHcNt4KclhFNK8VY7m1RTaCrh6xcuUYgeHthQz6eVW3xqVgJxh5OqNO7LylH74793qxmgul2ArFXNHioAKsTaDdqUZFrKmiKH19vxqV/52BiZWro5da5AqN8Ayx7n1Npf8my8J09LwuAXg2zoHPW/vAbyYWtdpIzhHC8qnBOhDIVjm/2JFCHO8lrI6t+6fGKzkBe3+Q0BekpkVNQjG0ItmbzcHv2BwqLEy9sou6sUyq3tMbOzQq6E0E7TT1KHX1U6V8zfCAO0zih/0nNu/d3+p/ICdx49rZLj2p6ZS9t/xDFDWvwjinIMUDqdJXydy+N/WB7ucn3yDwZ4F3YubxYa+o3SnXueEz5/CW/7r4QQAGblfw5K+QWvEb9OZSkrsS6eADRoyBAQ8GalYByQIWDZziOAJjYTZAnyUcdSxOIgGILUEGa9hUdHYHAI6iQHhal3edic2qL0HONmv1HWPz5ackMpCm6Xxwqc8gPywBAUNOUl9hhc/kmJMUZdj5vg7B/+l1wqVe8IXO7iHVv3+QNjCDTEGYFh5dRBS/Z18RcMNM9km5K0xzX19Q1zHYjRYt3BJz/QaNJmUJwdKfF+UX8oUe76x3wGX6p9NG6xTnaCRsfofnyOZ/dP4nQvDtBUQX18KVUqnN9pQfu9fMzOOli1SM03qJ/98MR9mm91Aw0t79dnE2zN27Z1LDrXqg+rrD1Tb6FaPGz9iS76DsbBJlbiL2H87S7stPxIVryPa1hHM5ObXXbIluREDDw/3RBOa98AfYf9vR9Yajj2j/IUJ3LNAqVjExaj8dFlS6aIZSZMOuamA2xQ8tH3+t32RmyoiS02M6EQZSdPMMpuY9TXwHlTHW6s2RmWADv/B+87AAdWTEgz0lhXezmjzTYLnVZ7duO1cWfcbSC0lAjLLSuLfvLkUxRARYDEzKtSrIs2ebzPhDIPKjyhVuT8yapogjGBPyqXtWGuepPPP4KOPaIanDih7A8qATCOxpT4ACA0Bhs2jZFb56zBH44BrLfbc0MP+aEytG6LobhTnUo/ik21z9EWYA+UFhTbatrJW1iv1KlGeh9K6ik5e42zw5eGxisNKw2OkVnbmB1Vq4zoyq8T03QyKAM3mmqgWgAaXd0FreGdRH6uENim2a4bHpO3ssbdjC5MRhpq/ec2mXgs7GTdngCGNmM+qFWmGk6VC9Eyc1Lixn7AHOOQeAyirOSzoSPLkdr+RNlrpIWlqg2ZVof6klBXLIS6Rd3wnAcBC7kXrHbeIACPI5IPxqjTC8CABeYm3NTG9i4hc85osFfr/EDEMRuPURvqLjGY6nfPFZlzMZePfXKRA6DAtyc22rKtP7tT4C/tFqa9wrbDJRkJ/+DLqq4ZjHWdC02MDQrbuyQ2AU2gTqG5g0CAPhW1urAY3xmxIdjeQzBWt8IpPtuwU7Lq1103Gm6bWHFhu8sfQtsPiq1cz2/9tAV+d6Mkv7MekRRh65SykH2QB8ouc33DF1ULp8KxcILOjk4QMKLuAWA+n6WiCAbnrhvXl6fnt9uu618KY7e14B2vXLZCxOJw+sHrqBwQkmyMsiE6te40LV2pwpygnMLFdci3ZaOXfq38Z/Nk3cJrHuzPM/O6uJNvdEgfA5q525EfLrYozrmganuYlJ9ccblWi64A0Gqy9NhBDMSxNUlTVZyI0pDw5hEKReYm9rHslgJ+Q6cXfWWcyR3K/iW59Vk+fMXEI3qx4o/+W/o9NGCdwIuj59QDmxyf6Duk/NbfXODLgMfDgGtO1niWi/8ln/2Rx0+41+YdiyTjugfzv/9Rl3u1QxSuHvMwrutP/NX/8t5v+zDvtf/hPHSAU+vznb5P6qnQn4nPKMq2nzR+9ZtNvtOj13rS236/7a8SfmebmvCMV9WmT9s81y88Bk21EBZTwfaHFUdeNCKrQA+spo9VgK/CRuFpx5/l6mKR2hvuukjNbfWh50qoARsQvs1j8ajE233KGEpxwOGA/bnbjh50g0dZ7YGvDq88BmWr2z736lGrs9l13NtvAVmlZ7MIAiiLUH/V274TyyihwnMmFEtyz+k1ZowvN+Fsvzw+rV2g8iDk4S9RdjZcv0o2DWxWYgAKMUlPU0e8iCrzTJ+gI72lMmoF6jrz9JcJ9C0TDwB+JDjQTbqNh76NcrFF+36iVJ2G2/MUP7FAGfs8mF1Ql4wcRhGAPzNJuAcFfrqgq8kOlBkA75aN74qZJSrzshDejudvkfGYyQTt7kELSziBlhPmEqU3ZzRn9nbTBlIdkD1v7fDZMZZFHhBuerpdNGDr7mcMnoJ2djzlUaGFexnqRsx9t5PpJS0V6y1acs3uTdj7OeY96Ce6VImZkQIk8ZdsF5s0psIUvarJYQqRAhz5RJQhVi0ZXCjZw4onTK0FclurGZ7uDbkpbfPG5Yds+fuhygxd5QGLBCBNGVKQtX+6LkZlai2rxTSwQVvpfrtqREl9V/k7DsVAe+L3iRIN5SXsWTl7BarBEnESma2dfwdUsfhzkl0oVFscxr5Ll5MuKpL32S5aMx5eq7pd6E2luk7BKydgyoo/L/nizb99Ibqp+l1mtBhpwDuBp9bB1vDqae3iH+iTsGdsSUgwXJd2KeEUhR8paFUeC++iE7DcvvkvP9RVGhzckbdMCZ3MEUyQ6zuqGjvmcFToo9AAxrYZLav2/dv+8lm77Id+l93inB2b7G0n5GDhqdPLEw8WCFFhbXlT0OemrV6WvCt7mXgieX930ub2ze5LU+TjqKz+8Any6Y/PWBjIgCkPjONwJy6YJOOSL5yQxw9suYX+zPO4dO4zt+xqPByz9ue3c34pdkLK2NJyGIdt4d/fHRxWvvTQK3xcHP1cXXJo4YKg9qaPPbnqzALEeZScToKJ3ggornKCIg37B10BT2UXQMvA6l/MSGL2UWrcAOqOZHxMkexdK4mEzeO61izfSczyMlsunpQiteas5MYNG/8deavmdw2rre63lwnqsN3yxUvuDRdESJs1Dbun9PRcaPMSQrHkjP3vDhdedlO7e0bbyghwtbqX5/F5fDRl7zeZrcPIyLkw8NwRpFdnl4zyR6/wrlyuYbZp0SDvvSNeBVEj1GEFdYV18KQhERhTOigCQ5//+JPkpy6O93nh/a7cXWdJC8mF14JlUfiunjDh5QyK47tSq+Ds5rrxufZlDvLe21kiWeaNJ7KFexbulW8r2CR8Jnz6UPRMFGVxxP8Zs0dx/Unmtgep5N1YFfViWPeHiN+fj47lg+BcbY4gq5SyH6TYU0viM3TQuSnC+MLq/Oq+/Es64mlVlOuFwvFQf5ASN8vajT7LwWulHA8s94+xP1uby4zZuTqOKMZgqfHL1OUZPe+dRqMclaAsk9q8iKoCj8IwJfuvNpJE25tu8zAHLRbWoKO0n6sTVKb8HqHZ7SZk55VSpQZcg1SKb5AYPNTcPB/pLEim3VVt5s4oL1mQ5jg2dqpkPqe0hD1da1TQak3KJrxsmmaaoglnVFBrMzbM+/IKJPmiVY91yXLWZvM7SSrzNK7dwxg0W5iD9tIBrl5Wg94ZoVlbQRTxPVSJAdcgk+IaZfoKqijdkCgd2wSShIuLWX8xkBKaPIEaiz0PksLoWUdzsRo8ixXc292qHlOrHMrSalNf2+GqMfUwBiQlypiVATW5ATXMSgVvtNi/OaC5KGf09kS1mTVkK+3lajQ9XGWxmSOX1JmluAaJwUXj5biaAb8aNaqXn8Nzjn41ZsBCuASDLN0Fzy5mqse2tUyr0nhlhbL86hR3gUvOm6hW4DvERc7cVU/NYOmchc2UqX/P5+BbZDiKEs+UYWWTxOiiYdpnZ5MuOHhCWJqjHtvdNFDlpMBF/72UP82a9UVoUVjrIaUWt6Lq/W4GVnHXCmfleqFmkAZfis5GDwz0JyMepY2sz1eTbyoJZJR4WAdncE0JZ0Gq18fvHrFMwIDeR635N11F/a+4yjtvWD38WkYFSZkL4kSEaqWqiigSVZIUSnwl/7BmZxrMlK1BcSqqWiv2qvdlLw2U4s6ooz/3vG81dnFeBoiu1F2uE9w+pY7eXn7aqT3n3OLU/SoKuq+8LjYHdTw1qKJOko/gzBO2oIY/+ihUNQW0Xht113etLH9pbsZOx2qQMHA4DdvDhJzW1m50zpWgi0MY4WxMaQdbN4RI3BCU8n+rKYGtucm5YdkVaxa74+t/Rf8VIfM4U3Nw/26YgWUQJVbWjOTiUCz3NJdZAh0NE752w3K2fNelhBpCfPDXqxCUbhq9iDK9nQlRkHwyuRuTleWKPfNJGVFww8TMohtSzmA8aonbWipmaFk2xvIdVLIEFoQwlb1gFtmTs9LtOJEUXy4SE8olUgc2PbMw+W24sk6XwiQIEKMwHTsNpn0jRBJpRsS3YWJTIH9KJYnPtWOEUly5lI/x5snz8exMEylDDndlRPf5eWw+K9dFWXC+JM9kBukZgXKlw6283GiMIR6kdTWt6bmgvGDlWwdUJrEcDAyAJOUpZOIKGbEknpvuiBZhPBh9L28WCt8/lmHIoKBFfUooyThnkBwurw2/8AJBQYnmKqFk8JR/WHGhK7d9yJ/piHZl+SeIx14vK0dRyqhGihgcNhKfclAJlqnSlTIeTyrncqTy3BT/GPqJQ7VsGJdeyLjar4IoI4o3FLGyzEaLpse771DiBAQymZj4FQJ5YR+PVcVy5qfeL44ukGWkh4+4QCI2NOkzukjF2hESi4KxaPL2v7tu/6fxyd6K26fHpSTXsh9zqfmMKwOqAX/4LqRemaKKzYrQHCpmZfIVqc8uudlZZq1F0zPSFMgc0I6VpOEUWjXdldRQEd4rltlxnHQbTijDe0V2q0hmA2tpaKoWMqG6S8+JOkdD2bHNkesEXUkDjwOAUyWROzBpFDl4fFQZfjMrQvPawuYt9sN6NBcfS8cqwk6KIikEAfwt3Nh/6GTsDRMzm65PzhFg3WIFySeXuzBZWc7QhK3KactPUMDymZ/FTFQOVKGZOpay2vxtKwyl0bLwdivfukURcXDKvCEt2UyP/Hf+6o6MQPnRKBX4231rt2urNoSsvbf4mnF31L+flOAFF+acMGyc3BO+DSe579/7LCl+P0g4xRiBPRdefhZc3vrrvu8+HwdaW/P1KjkRrKKgqaDjCMwsGuI4CIEmg5VEhV6dX5VTwb5OxkaZ8Fjg1obFAYs33AawuCgzlryTU7ZC3Hv+PxHoP3Q4OyjfoJITI1VkNI3BvlTEVRwpGVopmMgHwPjhyOjv6V/D48ttVgQnJqZOE+OTxxX1eHi4YoGwEMMJiKmzx1T+LysGiRZmbszrj6KqoXM1Q4pMRyyvU+tn8877u4e9Krm4wm6HTeeECTkSOE8iTJTTBo8OPzB9nvbXVY41NF+Q28n5ZeIbWfSV2gvl+rcjPy7bUbw5a3O5tPyfR+lOYWOZs4wojo7FFvrM6YOe0sEMq3WIa9SLmUkVlgUhz8nAm/WsflthN0Ot7mEUFDL79Y+b9hXaeo7exuzbk39ACiHS5MlEpI7BFKbi+FKjEUb3Lh9bhBIobQqFqpCPfhgynd5R4VmBZfTTMr15DaExKdnopNrrjeOnce2VT0Az2eFT+Wn/3+BciYI8hsNlLSOzwtb7F+2P2h2SJw75OSVKKyiLUCKRuPHZOS68VIJ3ZhPVqFd3Tjbe8goXY71uRbHZwrx2zEwnLv7lZlsnup2CMjC7SGjZT4Vt4gOsPIIbl0Sc0TqDz+DHrcDiVj99j8c/eroah1v17DE+6z48W/UdNGxiPgw2fyIMmiYQsNl5grSbFezGX53xaFNQna0u6uQ42724JCGpLYlQ0rMMJzcXa4klvcuwuGW9JVQzGzmVTYPtbGDD0lLl7C4qhh4grMn7QSH087H8GPKtf82+KKXwB/JujBIRl9v7GPHH9dF7MZ4gG4XdZg1JwNBC56E4ZP0CAoMfTSatrI1fq4xyvVAWPdQl/FTzR1LimxP1EMaJN0D8oJXfh2QjEWIkUoxAsmeeHv1XmvvqU5gkKF4hXfAofO5D0xNy051GzykcguZ/DCfs+eEiT+ZpKrL+9SbxpkQ68mrWUDAEBZyI0Ef4PkcqBltKXeQBbZA+DQIf8TueTAy2lrko/db7PBcNCRwND+5d0rsryYoa5XSk6w9fklexez2+cRmynRLIrnVbq0eamqZXa0qlFfex2pSyy1Cx8DuLz26jFSRYwiXfGGFkjiiDjXD/7iXqomeqMyqzMjIF6dxcOa/I958iSYnXV1jgclrQHy8tWT0rZVbFjNDXlQyGcNGB/X7u4hoj10X5FiSaUkkS5JYxkh/VpksJr0YXY+kEiZk5HVUcik+fOxgemxOWpdClTlx3MHMyTKT0QehS0ZAD5XKHSGTKB2nSN/0WLsBH6UOq4HdXwcmrmWwn9V1oKFjU598tob6pThqz2hovwK15lmE08Ezbppalzb721ZVmRU/iHDkZuJI8mZXEysrHUCPUObVvsk2hYKIQx5DDykWh4BCJnczGn/oeIiPbCr2DoQpUeO4jKZgY+JynXYAsyp79iKZpoI++ey7QLUgqer/GWNRcpr/wlXms9pLm/hfWEQFJkHQZqvsltBd/NveUEfb/jMycG6Zp0xxYKAiv8E5wRawqlnRAGYgBSTvRVka4xM2p1gh/L1L7evUOVrikgtunjCh1czRudlv5SReyDd+5Z5rt2CTNefUhTBIQL5OODHMUTVijklqrAthrchzZ8+0iz6+YovKJd56sEqsDlIgThIfQ+CS/7/RK5LZQ1OQguexi03LoidqjAhSZPPFTgi41NUH78wSZIkjekqjbGApur6h2+BzMjvWyT78WJAZZam+z0NfJD4+yio1inEypaMmajyMR4tcr5dfqvG4vrO8c8zOLJeAxISHPR6DQkeshh5MqkpLak5Jbk5K8OTzQRxgQQ6BDWhlIDOUwHnHgbw11y+2Oqxho7q6bJyMjVf2wjnFMBJtrv3hjsiRczfIxGn61JRQsSr1eDjw5VDGkCJPD5GvkYSti7IXvlxF8oOWkCTvSMzRIemFHJ0xcMeGwvZ8lTO6q+qCyDn5FsoT4wlH1fnnJMN/yvib2Lcc2yzUxTWOaua119jpvXWFdaR/S+9Me7NTe508GgXDDd5Ftl+c5MOmZBQhbuLRGl5Kur3YlmKOXExmYSBgCmw2Ps9dWmrj56DNhoiEPlpdRhJOLmM4dnsFSBAwcEx3tnp3mnppI7aXRuqkQCid5qmCA18/jp0ztMJq4pl4W3TWjbruo3w8vpzRtLueMjXckRwTeRu+aSoXO7XIvezDsCPrj4+syH9/IEr67b+1aDzHOcCnLLDmLM7566NMjLGd4By7zH6LPft+naXr90yzzjcwNBg2zl0/0/PgQ/v9I5J1XerCvpO8ff8UwhOeN3Moyi9Wvr+DqxRSllLk71MFZuRM1CiGlUmpjGrPIXbjVZVwQwk7j+KaZnnZY/JNDtPWO+NrKiPk5TwqZM09PWL2oC3HR8J0j/YnMH7XBDzwEiuMNHBBdbSN9ce7jR9FAzndksEhXvDzeBh/7xFk0kIuDmPRE+fsh9OBatfLXcGQIkTKte3buLBfIeFqXvr3tvZMHjYSvh5Av+9ink6d6tyf+xw9uhowf/uSP6MTf/zIi+D3187sg/JduWiyjvpu6H9qPbr69+vo53/2QGMJCI4WMjcxYJA1P75rGsMjdH/ZDRHpk6bwj30t+PIfe4MT+H9SCOOx/HoO6Z5oA2l46rmflbGr4qiPXH017YUK2NQFFuODB1ZpzIcTidffuXXgf1nz/5uTMCf2+/ySk/cYWFsrGTX62lMQqHnS8NGxmWnSDFlH4xsr9KQI0zgvSqtYWxdGTJbSKNflxwiF6pT77JujE/A3xOKLgipxHhccf3iSLoBEEi2YXx1Ws5TgFpda5n9GwVMJerGj55bctNHO2NUrFYuH8edkIG75NwO/7iyxZvTG6VgwJX31qVSSYVBcWXSdOBK869Rs4Etobpq4rykXmomlKp8OZ6LQ7laflriIXseJ7+tHU1Mv0xKAT9RBI/Yk3m5BYJJKNvzyw7JfiRV3wpNnGR7f+SYhnLSLvO5Vmn+2IR5JAR3OSRZPR2ykJran/B8fs/m41/J/ryXkB6P0x/zI6lgAIQHcx8LpAN4lHfMW1NW/o9RIxbv22Qe/2e1cPEiHdU/KhsckSInBcnptLgoEJeFz/iJdaFdJHjJVv2PKu9bQ9K5b2nbWFgEHM22NpxrmAAEEckNkOUifclu5YNj+25jFy2IyxCFj1x+sB9r/5APeueICH1zzAnsvFB5ET0t39wNW2M7vWv6LdxEdp7jr45gsbAYYUBRhPjC0GVk1+6u6Jv7NbFXq1hdmISBTUsH0aJBywfYWJ/1svIHsrsne/aD6UBcGhXWlicN/+176+dt9zCTYeWwy8yejjiZb+u7KMeRsnxRhb2jBvf/eyw7t3Te4xNADvndX80FNj703aIK2561mCJrNTe+fJverLsVfaKq15zmbJmP934fhb+rm0Axmor2Lvnft8k4cjDrWA9upz5yLaWoA3cZloEp7cmwbTpMVsRX46xwE4BbMYMjkbnS/NPbnb+P8HANlyZL/GCaCW9HnZgoZ5oxFoE23QF5NmRqNohN+D/Jhsvs+HsVWF/3OHXOg2iAz0n5FazbqRWMu6JFQILcBAR52TBFwh+AhNClYPycJrqkBXOsGYkB0S7cQORSl4Bf0C/P9BzopSC9aNVBPWJRhJu2cGwDjTND3DBsIGwOehECyQFPIOArIRA/f8P5DvLLTDjZIV0yJLT7/pjdX1KtW9KqBHr40cBWrEQyKcmKF4Cn7wi3cE4HAFAWJglKKCKmqhVmRGYx9RH+asuNYY1o3zBmDaZuekahYWScZwPWRjvcGc+dtL6IQvIeQ4kJxvNiaFZCgX5Q2NYiahYeZQ6IpVbCRWcxM2uQPmwx5Mq2aN0klTRf86zqoZScjuZQGB0GOGZbY6MFMA2cynKwJHrmmemefN5mqAXflhYa6Yx5EMcHCcjDCZn80ad6uCm8kZm2MGsw/NFpgjAViO5dUKxuVKmlfzQwC4TPSbydEC5QSwtt9I73uKgw/q9gL4DSRUX2gyKoFQhb8gV16WQ/okWwKYBolLZVtKmdHCCJAj44hKXysvYeT7AIvkiTJSgA0opHo+HVIMCC4g4BLKIM5fcnxNLakqUH4uLAEAB13WoBXZSBiicWiVvkA6ajKSvDOAgHqqcEDlyEAoRVxNim1hbSLxalTNqql7skZnS58EiyLqnPSQ2GKE7W137FnkMU+HP1z7on2BoL4lQnOxCkAp2D/S4Inu/QF0BdCR+RRcbw7WQcGcc+wpjVtS0y2Gg1Gf+UkhJD6CBPQLdUULgsiygMEgEdI5kIOUjGAQSoUYwD86Z6ENalDuB2XkP0AX+RcORZ/yeR1bs/Ktz6zZk+qkKxlKHk54TNGIXqmrdZce0g/r0OHlt7Bar221M+x99oFsA5H4dud1rW6Gu89BPEkbLDLHA7Ci7YoC9VKGF45gQ1GMLOUMwFMBphCHIVyI0ErKQtOBNq4kL7XSDLqPQhnajvBXlVe1qhnqPrUPuMz7DSgWsStNtekyQ+ZhE7pcLIb7bGgLcSWizL1PBBWwbmzourJY2a5oCMf9uMGi3oMrc939JFlUfbkXOzlgAF5hVvzwa6pkBRVEd9CLvPX8yqbT3navzJQq9jmlKU36CfqZkhpoWlAyGMWKBlwwVF4YROj+DeTK9qZQF2I6i4LWWhsJ90JKqmg+UsQ2jCYM1LkEY8C9zVhMMcoPxYYKHAmoaogWXMUh19mVKZXMx4zUlZRxvEcwPhwiZJMiaJcNm7mZK8U/+if63eoB1Aca43z6gPitINBFXfdop3P791r1HgjVacfgL9sZaV/HxNZj3WUl7PYxHOIBOi09kIQQKhcDNrvex45a1tqfd7VgQfajUy67cuJUeDL5zbwjh7FO46CwZLQj2JitMQj4/YoYVhfImfyApl0/XvpJtb++XqmyaqtFfZBWJ6lL+VgGo6vB31jy0+/UDrps1MlqDRdWCNKQLhAYgWB/kXjS4w7BeJkI9rXAoAgTTBEWzitwgXNrmhVUYU7S8Foo0k0SXSI6ocHxgkJrqWIdKpXoVF8szDuas5r+z5VBh0RaBzCAOZialRQjW9PUwWo1Bdx4kt+l0E3N7Q9Vx+qWMD1Qi/s/GOvKDO7sqQYIDrqck3JCJJ+SSsGXQIzYVqU+rhUkumwSwqHpxLIj60tvR0x3qsOTw9FEgdZWVcOjbaUIdidq5dReoBBQ/tDSMKAOx0sfM0TQ0Jh9wMMSFCOcGPgNKIwMN0pqIHnrNTZPbo6VQ4o3252TCq/flYU2TPUI3pT5pRlvHsgKTDRtybSnsoDiSxZD8YhfqAHFWNR3IlG6AxBS4Rktrn35rZdoaYffhz2cFbHYSBKheMCJ8M4TArRW71TgiZR0SW5mhcAjbvxTDDTYgdKymiFGqNtM78fia5lrL0TPCAYEaiB9pjkjy6tvBhI4QDowEqAmWKuWeyljKwdepoM1I0RvT/S1RHeJP6VQl6qBfoDrh4S+W+n7tD7IxCfYZfu9vFty7RN9mxKl5+J0vR96V0p7uFDyk4YDCI9ImpBIHx+orKxx1/GW9qCFKrJSBW2DiuyEWGf7QM5nvuLk+kauNwh9gIivkou0jvI0aYAvEjYUVlxVXd8J5J2k8PYX84tylvPOIRZyQnDJNm6Wqthh1IDcG1lgT0swGxy5gFWk6DPivn4H7DOFwBJIccYzOEPi4CKJAC6hnQyBZGnAZiP5VKhcFuElNRXsSkA4PYEV5j83d2RkAf0orglyTIlgDwNGlWPJH4txJA26Na5h0NnFRk4++Okm6yq0MkGVtkmLtwwYDMeyXKODH3ch3mCwX0E/wAFssCVN7GYkZ8bZ7B1UxwdYhIi+20nX4S8iEyM8FUkRVZKoRpA0ar/Lmsc+TVPqh7SoFWVpA7UHMSlP90lT4qoSq7wnxTqRuYTWDal6rp90uf9ac7TKIgXNjQBakhG7wdBjWKVTf+F8t5uKi+qjHRDM4gbnqrZWtjVW1iussdbHPRE/4tARB/3SzTjCfudUaOedDxTbuybbfj+rwJ49XOfyl7hfEWLud2Y4VC4sh4erpohah7EODw6MFRivre5upve879YW53I9wJzmDyu0qmk+zoMejEppZRCg6F1QK8RDIAwDrxWJeH2wDqzMFtJb+tTDC9Wm90RlQuX9fdBCl/J0UKIptTK3OYaVSvXzzcKaXCVpNS7hm56RE86c/7nEl4ZZ2iNuqhSbVgOWRITnk6I25wo2BhOp2IkzWrYS4Qwm28n7oWawfvY6n+0rRmUkctZVXYwzG5BY0+hRglHHuxqMZL5QsbmxL7aDYVuEk0HFDVOioXXq3RhOH6OH38vldVR53BW1VjQyaUSn80ofyBb0ku4Ud0W4R6G4g7VsREF72XdwqEymeT2mlfm+z8Ya/DGJioxWNSQKByA6H64ZOJCeIvpVQn4yxMW3URY3ielmC/uYaEIpk4kMpBWG+RekSytlCImwjVhoCrgXhdZBztTyVviHqIxzuydm9G2FrjMU4clO2WehVM1hBVXj8Q4hNA8qjKQvEPoitXMT/fkeO32X+8Gd79c0FwUFZIVn5Mcciy0D3PNEeYrs5iwSZIdcnmSzGznSK/sZiW1p0bCwMmbpfOrQnVICDtCocGBUIM5dCSNGC2zZqmmCu70FJESNROnrqSuss4vDpJeMvxDG851mUwxbUQ/0I7Kh9Jw0hiSTQuArvkoN7qnS7cKyUdB5vXTDBoBoVUIMLo12yszjllmpaKiqZ+LTvCA0ex6MHXVf+GxEPPxY/T/te2lTmZwL8yc1HeXR9Ii0CyObwmQ4Azof4TQqyKGPQFgk+xNJgSw0LHEJbFeatXTYnhbtAlRRTRu1laJmY+LiiQIvssRSGx1mg+ACDH/SFn0dJ+jb8wc2GNHlVuEqIg047BPsBXI4rckl3EAPRkBGN7Tfp+Cd1wsl8UYaWs19VIUz+3HOJ3fNJrObcRif6TazzSPGCMMZZulzQaw4Dv228CTGEUsuPT557UeE8sZaTFDpM5Eoso9EAFmmIMC8PNnUrbnRNz38E2DTRM526J4jXkzoDtucUXSbNaEzffs1RQlrWsclA0x3j1Nqu37Ndjwbb2bYjhdZetLms80Oi6cKRtZGmrKxsKPxN4wLqSENACrsm0VgJW0Ub/x2TzAclCFrGDLgq4flkLK0nBWVgikkOw0YRgYz7aDTID4kZrxV3ZBy3Gx0GkPDWXM054xzQPM9cG5TtdJg4azyDfjpja6dU8kKu/aF0nWycUi5gXYJZ+ZujeNNK9aRoLhnYiyThgPTBebz5c1i/khnunvFTBSrt1bnnutkzVDWFOuvumI9H+GU+e23s01FrDLQAelTZE4xsnZ9cZ2IWNHS+UzIgjgnh4+JviWKwryqynF+Hz5pOlIqW+1kIye/A8RKRrwr8YLEonnXE0zcpXQI60ChRM06uokC5J0JFCTjurlCKfFjKQVj0Iy7FLmx9dHRTPkXe3KBDZtv3c78reKvsLTXW7Gbz+elfn+1r7eWMD+B6Xo+vtL32vjMOKdlJUtxdHXr22VVQQcogTN7Q6f4OdRFgTiTEYH4Ja2lwojRsHMSOy23ptkov9OZQTK0DMuGLcNAbocaX7BoLmTov7INgsGe6pLzNOuGgQqCI4S+5B0oIS4XC4sV6dqQtIrIBlbCrTElFnkxdqyCQ+ento0hEhaZqBEVL4OA6MZ4jDyEfFqJVpE1Qgg9Wngp5EialgoSUNNHSfhayvKJ5daP5Cldto6JiwA62CQ6KLP7RsodKyqhKj9eJp1rsLIxRadaNfu26h4GP748PapC63vObn+jJOmwmMQtFrzEN2KbfuDYrRmVJVuxjI1qzXDYOt9yM0JzEWUr6CR4b5kpsHluEG+9UOICyaRm6kYhk/+3C61hq2phabOXdETscXNm+LDWHc2FfEYmK70dAUWhw0UUMohysfsdqi1vuRJbypovq9cLhZP3TjrOnTgXww/jpCauBEW1bXonoGYyf0azrWRzTPrVesK0h5qrlfQapUsq9CepVxlxI2xbebkU7ZaV9O7AlqKoyRFH2OiWonmin9XJfTczOe8lrQd+0Q5DbJg8LwrXU0K3pe6oeFI/TP82lwmkJnxSsCZr9nASnBBRy7Vo1Z6nul6HdZjhdLGrsQg9PVMAWG1pdhyZhrnsV+mOOsLgH6LSMof9oCqg93Wo1+6rVnVEmNiVKTD/CLbnlw1grXyGdo/PN6eG58LEWPljNQFfZV8ZnxLHej5W2pjHaoa6EZXPakw81qrSfZgsJRuliPuZW7vRoHLRVGKCWS1Uqlr3VadGnXfqyRdMymiNp1F6jtLS8eqf0iui1Jl4E5C7jlSFZ6qEsUWzU9/LbZKABBUTmZbKiha7lxwEUtA0RpJaqitxP5Kp0rSyG5X3NvJt6o2wDZ6EsnJvCSuQ1p6C3KdUQMk25ibkp1DvRnrPCGihi1Ur3UqOuA6+LF4quxND4koa45ZaQIiF4yiFbHhh0VSfbxbS8i2kUK8HUEw1cX6ZCIjlw/zdAFCXdjvffyqHTs4aZrNFud5oM+m1bRXldqPjSa9qY1ur6vdh21Q9nCpXOZVmy1AjsF4ewqNMMyKWEI/2UXiAz3TCdJ8oqLdRukdhiDMS/1Nk4RoYzqzdgnGwW81Wjyh+pQa81WGRFyy8BWSNCsg9FGrbXyDYawSLitBvTFf3IghMh2TkjD0VvJBGJhlye7lQlv9CL5WhbgQyqK7Qw+GJQAfzawWMgKl2UJQVwjuCRBNNiWOr6dOdIbMdTcG6sbakGqhu0rhh8wxKk/B4s8xXwbXMBPXNHJugzOKlKH3S/pqw/GCt9Tz/exLQPV4W7oxWWe3WprnqWcTofoAOdCnrM/WKTI20eEEF195BWGmIbHdxeFLUIpackLsdMfHIb1TKH98YYbZiG/RONHCA44e0HTBc3TW8IYrbXloCOEoGB+31hbRST87P6z8HaERqBJ8Sh5xtj/PaLcuL2++wM9lwFNbBQX6FeedKCy1bKm9W/PdkgG3Mb/AJzL2/RJ8HSWmXEgIy+4A8DFbkCSRlHMEi4Ro0RmsvBjwxu2WWdBakbb27ZUz6EMTQ4V9shrFNHm/aXi8+TFCwwpSYlFSvkR7fipKKHGronTq79owd1UlyWW1jJImkXh7VkK4CPEe4wsdRSMVSjMMc1UY68yxBJteWGyPLOQfqV1m1Cbyw456wCkIrjSK7U/VSlE74rtebcfwbksZ6hckLmGTgIDsdJFsjDdM/6OGAXr99ykbSGuYsHET9BvYlq0R4xNCoWbS4Arqdr0zbKSLaheOuLwvW1yJ1Rc1MMQsY0XchFFdYejSKR6bp4GD15Dc655qu5/LDM4FM7WBZUdpM4QwadhTlX/UTMte4wKXPPck5nIz4/iEwdMMZgnvAQxlUf3OhTuK5Tc6qcQjxj5VnQD/Nmx1j6CA88wzv2zcgcfTb4VNgA6Eqr/U9cI1pitTQvgb9FblUhbLBRUy97YN7LU0jq0lMPxUi0XhekFDl1mNwuQn6jSpYhsvdq1F9DwUCC+ucbEGwki7l5gLmQnal2FeO7XxUSzspU9HKPsuDslpYDnRtWfVvagQX5BfwOCZI7qatczYLUGIo3xJlG7Wi1q+9Oa4ITKJXl8x/XIUwT/ukvwz1/3iYvxH/NgrhMZxaOa+Z9TI6SC4uuVQ2kv1uMgAkWQJD11uB0oDXRzStVe7BFlVIGkmR0AZ7L2qvL+Au3JekgAD3aAyNX/uzM4r3f2iK/hsRwI9+2bM2/Kj4//jXh4Gr9JdEoCABAgAEol8eRBM78WB88krgKlIAN/koUZBGefpcwNjfxPQkzjhO1Fc4voMhZ+XnrIzclts24gTDbP4RnmA4sK453mE21eImWkaiGa4PdKUUekqsJXHuJ6ktVtV9ZCPIJGOo+fV5W1lC3tWafxvjgYKR3lUNkhkGNQv9/JzCpC8VdULqgkqZ3c2im5l2Mc/c0VYXZO6QlESpNRsVymk9Zwk8KsaLB7lGKa3iDERiIPNr8ZAtHvsBlkpaidcmNKuXl5kMSmUicpbl4rYpnMPXdU4DmsS3drL+xL4IbaODOJtEtFhaV9FShKaME2DlsQAQn1vLFpsVp8b8OAi6Do19onjJJ+DmH4TMDzgAKLeq6mHkfANRHusMDnhQQZ7jKcUQnS/Xf2gjHgSBxQHgBgK8cpxNwI1YwjhEMh7iSWTIMVCEWoHrcSN+gzfwFZwnhMgLGDdKMGzFiys35hghFm3MzxmVgwYDaZaGZpKuoD/+YNPNdu6j9cBifBAvwFXYh2uxA9fjJnxmZH7e+wGnZcRxL/gBXGkYNAQJ3B8WoA4o8B384YQMshkBAAAfQK8QE3wUinSMokA4Oay4riiZV6MoYx5XVBzvWwWcgjqqsAbF4N9VSbHQ0aytF/ZBCWBLZ2FHH45QjM2AQ5Tpnis1KArO13uVBBpMKBoylobNumLhVoNSHHh2qcLwpblW8TCx28IBlJT+xp6s1GAl7Nw2C9dBacC1oSbcog+3UehUfFvLlt0z7cVB/DkIPf5p3jL5iQR2Ie0YvG7AaThIW+GK9qyGqVCFCr0GvBR4gFOjcpVJp1cn52dnqCrrT835yWnTsTzYh/T0V3+7/w2i90WTYb0yrWsdxOyc+CcmzdSGmpxEcuJbgEDiq0E0Rf5YCQh3RdmBFVUzGOAsPMwrTzV/8gTensoTzbDn94Ti4o24RYD1nqilTwuV4ZrVq4cFrCWsnZPVBlKWmzRuSy/mBu9GNsqRjbDccE1B7wh4HCnAw6ghs9rRV4QKI0iRRpgXWtY3iQxhQMkbQ6C7WHbv2XzX6maGj9nNIFnd7tQOKiZRMyjIN9qgFBj0W0emJmhyNX7+VHcR6mts5z5MI+hENbkmOgEHB9zViefzZOMFlyYpRIX9Fwdwent71cHZyekpvGXyEwnsQgLfALVUy93xKK5/uBtthYNgic1Ynrn9t7vb3n54gATn5TuFOqGcXp2cn539Fjh+SZz1+OZcx0r4KsCV+4jd+JRXf7VOfSNE45zzQlxumjyze/gHr9OV6p+YwhFlavDDEsfyj1kOaBpJC0wwgPyioy14fPnZGwsS2JplzEYgAVOyRwYPLCT3leaYY8OZ2aWi4mVsqLAfc4kcNeblXQx38WcUzxaZ6orXSKgqX+McK5Y6hXGhTVcO/g3hqiiZp1gdmxusW89YrOPPHKcVdPh9Vc06JizYxdaZsc0gLVg8TwBzIB1Dn2EeBPi1nIJzLEvTc84pjGG5QhHIlBbz0nbGU59Fy6l2oPLfAl+Z+eVfSHonrPtwtR/IUqkn7KfIvnlxg/1YYvcZwEicE7KWzZmr02MRMTj/zXaWnAN2Pcd9aOJ1hQtxThffeX91uZDNwcw8H+sYgnNk+vbY3h3qATjHxFWggST79VbIMmqpkynh2S3csaLKQU52fwlu1/0XEPbwqWcBzfNdZadjtzP0t3aLdc+mzT7t7ctPk5fZ/T0/xf/GNB1X4vi8PjjRv9p4HiEJaT9Zl6WcHgOGjBgzZcaSFWs27Nhz4MiJMxeu3LiPsNff6z5ExCSkZBSUVNQ0tHT0DIxMzCwK2DgUKeHkMt2gJVPGbTpkzEvTTLrjhjUO2+2YR474U55SIwo8dsFZ5/yl2HxPjRpT6annBpWp4lOrRp11qjVq0KRZqxZt2j3RoUunbr16rPfNC9s9c8ddfzvlsx2+uuy2cddcd8sVN/3rjPMuuGujc+6Z6YjrbnwcCcxBigw5CpSoUKNBix76GGCIDmMwFuOY1NIqvBktL1MN22irkrFYnseaA0qdJ6y6kHpih9WcDU4zt9vcQXaa+bSk2kTr2uBS3CbjQi+0eWxb0+RODtyZ0W56zccuUaMUSMcv6VgbxSFmawt5B847nhUCW7HSfLSrX/CnCbuxGNJHGFNP9GD8CG/NyyHQJShJuuptLw7H/oHf9cT0jQ757jHdP3F12jrLmkMv8oXJ7dgb7j7gOPpq79Qbzj5ulf/hGxcdeBAdUwfs1EP2PS3S1dtd9LATd4/yV8lJVvz4XSqcPCSPuujsvbcjNJjsCvStc/bwhMNzLpEj97lRsCZwsODt0rzxQwfX3igLptCE6/5EyDw4jyNYhNXoysiCdRM=); - font-weight: 400; - font-style: normal; -} - -html, body, section, ul, li, nav, a, h1, h2 { - padding: 0; - margin: 0; - outline: none; - text-shadow: none; - box-shadow: none; - border-radius: 0; - text-decoration: none; -} - -body { - font-family: "Whitney SSm A", "Whitney SSm B", "Lato", "Lucida Grande", "Lucida Sans Unicode", Tahoma, Sans-Serif; - font-size: 17px; - line-height: 1.5em; -} - -::-webkit-input-placeholder { /* Chrome/Opera/Safari */ - color: inherit; -} -::-moz-placeholder { /* Firefox 19+ */ - color: inherit; -} -:-ms-input-placeholder { /* IE 10+ */ - color: inherit; -} -:-moz-placeholder { /* Firefox 18- */ - color: inherit; -} - -h1 { - font-size: 25px; - text-align: center; - color: #38a8e0; - padding: 20px; -} - -h1 p { - font-size: 17px; - font-weight: normal; -} - -h2 { - font-size: 22px; -} - -.logo { - float: left; - margin-right: 20px; - display: block; -} - -.logo img { - height: 55px; -} - -nav { - margin-top: 17px; - text-align: right; -} - -header { - height: 50px; -} - -section, header { - border-bottom: 1px solid #95d4e7; -} - -section, header, footer { - padding: 5px 20px; -} - -ul li, nav li { - list-style: none; - display: inline-block; -} - -a { - margin: 0 10px; -} - -a, h2 { - color: #EC008C; -} - -a:hover { - color: #671345; -} - -.highlighted { - color: #EC008C; -} - -.make-center { - text-align: center; -} - -button { - -moz-box-shadow:inset 0px 39px 0px -24px #e67a73; - -webkit-box-shadow:inset 0px 39px 0px -24px #e67a73; - box-shadow:inset 0px 39px 0px -24px #e67a73; - background-color:#e4685d; - -moz-border-radius:4px; - -webkit-border-radius:4px; - border-radius:4px; - border:1px solid #ffffff; - display:inline-block; - cursor:pointer; - color:#ffffff; - padding:6px 15px; - text-decoration:none; - text-shadow:0px 1px 0px #b23e35; -} -button:hover { - background-color:#eb675e; -} -button:active { - position:relative; - top:1px; -} - -button[disabled], input[disabled] { - background: transparent!important; - box-shadow: none!important; - text-shadow: none!important; - color: #dcd7d7!important; - border: 1px solid #dcd7d7!important; - cursor: not-allowed!important; -} - -.menu-explorer { - color: transparent!important; - display: block; - display: none; - text-align: center; - position: absolute; - margin-right: 12px; - margin-top: 12px; - right: 0; -} - -.menu-explorer img { - vertical-align: middle; - width: 25px; -} - -@media all and (max-width: 900px) { - tr, td, .logo { - display: block; - } - - .logo { - text-align: center; - } - - nav li { - border: 0; - display: block; - text-align: right; - } - - nav li img { - float: right; - margin-right: 0; - margin-left: 12px; - } - - nav { - height: auto; - margin: 0; - display: none; - - position: fixed; - left: auto; - right: 0; - top: 0; - z-index: 9; - background: white; - width: auto; - height: 100%; - box-shadow: rgb(84, 145, 208) 0px 0 0px 2px; - } - - nav li { - border-bottom: 1px solid rgb(84, 145, 208); - text-align: center; - line-height: 2; - } - - nav li a { - padding-right: 3px; - } - - .menu-explorer { - display: block; - } - - .header { - position: static; - border: 0; - box-shadow: rgb(84, 145, 208) 0px 2px 0px 0px; - } - - .no-mobile { - display: none!important; - opacity: 0!important; - visibility: hidden!important; - z-index: -1!important; - width: 0!important; - height: 0!important; - overflow: hidden!important; - border: 0!important; - box-shadow: none!important; - } - - nav a, .menu-explorer { - font-size: 15px; - } -} - -@media all and (max-width: 620px) { - button, input { - display: block; - margin: 5px 10px; - } -} - -@media all and (max-width: 500px) { - h1 { - font-size: 18px; - } -} - -@media screen and (orientation:portrait) and (min-width: 350px) { - .header { - position: fixed!important; - border-bottom: 1px solid white!important; - box-shadow: rgb(84, 145, 208) 0px 1px 0px 0px!important; - } -} diff --git a/static/kevin-master/assets/fonts/FontAwesome.otf b/static/kevin-master/assets/fonts/FontAwesome.otf deleted file mode 100644 index 401ec0f..0000000 Binary files a/static/kevin-master/assets/fonts/FontAwesome.otf and /dev/null differ diff --git a/static/kevin-master/assets/fonts/Lato.css b/static/kevin-master/assets/fonts/Lato.css deleted file mode 100644 index 49a28fd..0000000 --- a/static/kevin-master/assets/fonts/Lato.css +++ /dev/null @@ -1,36 +0,0 @@ -@font-face { - font-family: 'Lato'; - font-style: italic; - font-weight: 300; - src: url(S6u_w4BMUTPHjxsI9w2_Gwfo.ttf) format('truetype'); -} -@font-face { - font-family: 'Lato'; - font-style: italic; - font-weight: 400; - src: url(S6u8w4BMUTPHjxsAXC-v.ttf) format('truetype'); -} -@font-face { - font-family: 'Lato'; - font-style: italic; - font-weight: 700; - src: url(S6u_w4BMUTPHjxsI5wq_Gwfo.ttf) format('truetype'); -} -@font-face { - font-family: 'Lato'; - font-style: normal; - font-weight: 300; - src: url(S6u9w4BMUTPHh7USSwiPHA.ttf) format('truetype'); -} -@font-face { - font-family: 'Lato'; - font-style: normal; - font-weight: 400; - src: url(S6uyw4BMUTPHjx4wWw.ttf) format('truetype'); -} -@font-face { - font-family: 'Lato'; - font-style: normal; - font-weight: 700; - src: url(S6u9w4BMUTPHh6UVSwiPHA.ttf) format('truetype'); -} diff --git a/static/kevin-master/assets/fonts/MaterialIcons-Regular.eot b/static/kevin-master/assets/fonts/MaterialIcons-Regular.eot deleted file mode 100644 index 70508eb..0000000 Binary files a/static/kevin-master/assets/fonts/MaterialIcons-Regular.eot and /dev/null differ diff --git a/static/kevin-master/assets/fonts/MaterialIcons-Regular.svg b/static/kevin-master/assets/fonts/MaterialIcons-Regular.svg deleted file mode 100644 index a449327..0000000 --- a/static/kevin-master/assets/fonts/MaterialIcons-Regular.svg +++ /dev/null @@ -1,2373 +0,0 @@ - - - - - -Created by FontForge 20151118 at Mon Feb 8 11:58:02 2016 - By shyndman -Copyright 2015 Google, Inc. All Rights Reserved. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/static/kevin-master/assets/fonts/MaterialIcons-Regular.ttf b/static/kevin-master/assets/fonts/MaterialIcons-Regular.ttf deleted file mode 100644 index 7015564..0000000 Binary files a/static/kevin-master/assets/fonts/MaterialIcons-Regular.ttf and /dev/null differ diff --git a/static/kevin-master/assets/fonts/MaterialIcons-Regular.woff b/static/kevin-master/assets/fonts/MaterialIcons-Regular.woff deleted file mode 100644 index b648a3e..0000000 Binary files a/static/kevin-master/assets/fonts/MaterialIcons-Regular.woff and /dev/null differ diff --git a/static/kevin-master/assets/fonts/MaterialIcons-Regular.woff2 b/static/kevin-master/assets/fonts/MaterialIcons-Regular.woff2 deleted file mode 100644 index 9fa2112..0000000 Binary files a/static/kevin-master/assets/fonts/MaterialIcons-Regular.woff2 and /dev/null differ diff --git a/static/kevin-master/assets/fonts/S6u8w4BMUTPHjxsAXC-v.ttf b/static/kevin-master/assets/fonts/S6u8w4BMUTPHjxsAXC-v.ttf deleted file mode 100644 index cf3da8b..0000000 Binary files a/static/kevin-master/assets/fonts/S6u8w4BMUTPHjxsAXC-v.ttf and /dev/null differ diff --git a/static/kevin-master/assets/fonts/S6u9w4BMUTPHh6UVSwiPHA.ttf b/static/kevin-master/assets/fonts/S6u9w4BMUTPHh6UVSwiPHA.ttf deleted file mode 100644 index 4f3d844..0000000 Binary files a/static/kevin-master/assets/fonts/S6u9w4BMUTPHh6UVSwiPHA.ttf and /dev/null differ diff --git a/static/kevin-master/assets/fonts/S6u9w4BMUTPHh7USSwiPHA.ttf b/static/kevin-master/assets/fonts/S6u9w4BMUTPHh7USSwiPHA.ttf deleted file mode 100644 index 45f7947..0000000 Binary files a/static/kevin-master/assets/fonts/S6u9w4BMUTPHh7USSwiPHA.ttf and /dev/null differ diff --git a/static/kevin-master/assets/fonts/S6u_w4BMUTPHjxsI5wq_Gwfo.ttf b/static/kevin-master/assets/fonts/S6u_w4BMUTPHjxsI5wq_Gwfo.ttf deleted file mode 100644 index 96b4f82..0000000 Binary files a/static/kevin-master/assets/fonts/S6u_w4BMUTPHjxsI5wq_Gwfo.ttf and /dev/null differ diff --git a/static/kevin-master/assets/fonts/S6u_w4BMUTPHjxsI9w2_Gwfo.ttf b/static/kevin-master/assets/fonts/S6u_w4BMUTPHjxsI9w2_Gwfo.ttf deleted file mode 100644 index e8d349b..0000000 Binary files a/static/kevin-master/assets/fonts/S6u_w4BMUTPHjxsI9w2_Gwfo.ttf and /dev/null differ diff --git a/static/kevin-master/assets/fonts/S6uyw4BMUTPHjx4wWw.ttf b/static/kevin-master/assets/fonts/S6uyw4BMUTPHjx4wWw.ttf deleted file mode 100644 index 3c2d417..0000000 Binary files a/static/kevin-master/assets/fonts/S6uyw4BMUTPHjx4wWw.ttf and /dev/null differ diff --git a/static/kevin-master/assets/fonts/Simple-Line-Icons.eot b/static/kevin-master/assets/fonts/Simple-Line-Icons.eot deleted file mode 100644 index f0ca6e8..0000000 Binary files a/static/kevin-master/assets/fonts/Simple-Line-Icons.eot and /dev/null differ diff --git a/static/kevin-master/assets/fonts/Simple-Line-Icons.svg b/static/kevin-master/assets/fonts/Simple-Line-Icons.svg deleted file mode 100644 index 4988524..0000000 --- a/static/kevin-master/assets/fonts/Simple-Line-Icons.svg +++ /dev/null @@ -1,200 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/static/kevin-master/assets/fonts/Simple-Line-Icons.ttf b/static/kevin-master/assets/fonts/Simple-Line-Icons.ttf deleted file mode 100644 index 6ecb686..0000000 Binary files a/static/kevin-master/assets/fonts/Simple-Line-Icons.ttf and /dev/null differ diff --git a/static/kevin-master/assets/fonts/Simple-Line-Icons.woff b/static/kevin-master/assets/fonts/Simple-Line-Icons.woff deleted file mode 100644 index b17d694..0000000 Binary files a/static/kevin-master/assets/fonts/Simple-Line-Icons.woff and /dev/null differ diff --git a/static/kevin-master/assets/fonts/Simple-Line-Icons.woff2 b/static/kevin-master/assets/fonts/Simple-Line-Icons.woff2 deleted file mode 100644 index c49fccf..0000000 Binary files a/static/kevin-master/assets/fonts/Simple-Line-Icons.woff2 and /dev/null differ diff --git a/static/kevin-master/assets/fonts/font-awesome.min.css b/static/kevin-master/assets/fonts/font-awesome.min.css deleted file mode 100644 index 540440c..0000000 --- a/static/kevin-master/assets/fonts/font-awesome.min.css +++ /dev/null @@ -1,4 +0,0 @@ -/*! - * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome - * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.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} diff --git a/static/kevin-master/assets/fonts/fontawesome-webfont.eot b/static/kevin-master/assets/fonts/fontawesome-webfont.eot deleted file mode 100644 index e9f60ca..0000000 Binary files a/static/kevin-master/assets/fonts/fontawesome-webfont.eot and /dev/null differ diff --git a/static/kevin-master/assets/fonts/fontawesome-webfont.svg b/static/kevin-master/assets/fonts/fontawesome-webfont.svg deleted file mode 100644 index 855c845..0000000 --- a/static/kevin-master/assets/fonts/fontawesome-webfont.svg +++ /dev/null @@ -1,2671 +0,0 @@ - - - - -Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 - By ,,, -Copyright Dave Gandy 2016. All rights reserved. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/static/kevin-master/assets/fonts/fontawesome-webfont.ttf b/static/kevin-master/assets/fonts/fontawesome-webfont.ttf deleted file mode 100644 index 35acda2..0000000 Binary files a/static/kevin-master/assets/fonts/fontawesome-webfont.ttf and /dev/null differ diff --git a/static/kevin-master/assets/fonts/fontawesome-webfont.woff b/static/kevin-master/assets/fonts/fontawesome-webfont.woff deleted file mode 100644 index 400014a..0000000 Binary files a/static/kevin-master/assets/fonts/fontawesome-webfont.woff and /dev/null differ diff --git a/static/kevin-master/assets/fonts/fontawesome-webfont.woff2 b/static/kevin-master/assets/fonts/fontawesome-webfont.woff2 deleted file mode 100644 index 4d13fc6..0000000 Binary files a/static/kevin-master/assets/fonts/fontawesome-webfont.woff2 and /dev/null differ diff --git a/static/kevin-master/assets/fonts/material-icons.min.css b/static/kevin-master/assets/fonts/material-icons.min.css deleted file mode 100644 index a14ee13..0000000 --- a/static/kevin-master/assets/fonts/material-icons.min.css +++ /dev/null @@ -1 +0,0 @@ -@font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(MaterialIcons-Regular.eot);src:local('Material Icons'),local('MaterialIcons-Regular'),url(MaterialIcons-Regular.woff2) format('woff2'),url(MaterialIcons-Regular.woff) format('woff'),url(MaterialIcons-Regular.ttf) format('truetype')}.material-icons{font-family:'Material Icons';font-weight:400;font-style:normal;font-size:24px;display:inline-block;line-height:1;text-transform:none;letter-spacing:normal;word-wrap:normal;white-space:nowrap;direction:ltr;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;font-feature-settings:'liga'} \ No newline at end of file diff --git a/static/kevin-master/assets/fonts/simple-line-icons.min.css b/static/kevin-master/assets/fonts/simple-line-icons.min.css deleted file mode 100644 index df0e45f..0000000 --- a/static/kevin-master/assets/fonts/simple-line-icons.min.css +++ /dev/null @@ -1 +0,0 @@ -@font-face{font-family:simple-line-icons;src:url(../fonts/Simple-Line-Icons.eot?v=2.4.0);src:url(../fonts/Simple-Line-Icons.eot?v=2.4.0#iefix) format('embedded-opentype'),url(../fonts/Simple-Line-Icons.woff2?v=2.4.0) format('woff2'),url(../fonts/Simple-Line-Icons.ttf?v=2.4.0) format('truetype'),url(../fonts/Simple-Line-Icons.woff?v=2.4.0) format('woff'),url(../fonts/Simple-Line-Icons.svg?v=2.4.0#simple-line-icons) format('svg');font-weight:400;font-style:normal}.icon-action-redo,.icon-action-undo,.icon-anchor,.icon-arrow-down,.icon-arrow-down-circle,.icon-arrow-left,.icon-arrow-left-circle,.icon-arrow-right,.icon-arrow-right-circle,.icon-arrow-up,.icon-arrow-up-circle,.icon-badge,.icon-bag,.icon-ban,.icon-basket,.icon-basket-loaded,.icon-bell,.icon-book-open,.icon-briefcase,.icon-bubble,.icon-bubbles,.icon-bulb,.icon-calculator,.icon-calendar,.icon-call-end,.icon-call-in,.icon-call-out,.icon-camera,.icon-camrecorder,.icon-chart,.icon-check,.icon-chemistry,.icon-clock,.icon-close,.icon-cloud-download,.icon-cloud-upload,.icon-compass,.icon-control-end,.icon-control-forward,.icon-control-pause,.icon-control-play,.icon-control-rewind,.icon-control-start,.icon-credit-card,.icon-crop,.icon-cup,.icon-cursor,.icon-cursor-move,.icon-diamond,.icon-direction,.icon-directions,.icon-disc,.icon-dislike,.icon-doc,.icon-docs,.icon-drawer,.icon-drop,.icon-earphones,.icon-earphones-alt,.icon-emotsmile,.icon-energy,.icon-envelope,.icon-envelope-letter,.icon-envelope-open,.icon-equalizer,.icon-event,.icon-exclamation,.icon-eye,.icon-eyeglass,.icon-feed,.icon-film,.icon-fire,.icon-flag,.icon-folder,.icon-folder-alt,.icon-frame,.icon-game-controller,.icon-ghost,.icon-globe,.icon-globe-alt,.icon-graduation,.icon-graph,.icon-grid,.icon-handbag,.icon-heart,.icon-home,.icon-hourglass,.icon-info,.icon-key,.icon-layers,.icon-like,.icon-link,.icon-list,.icon-location-pin,.icon-lock,.icon-lock-open,.icon-login,.icon-logout,.icon-loop,.icon-magic-wand,.icon-magnet,.icon-magnifier,.icon-magnifier-add,.icon-magnifier-remove,.icon-map,.icon-menu,.icon-microphone,.icon-minus,.icon-mouse,.icon-music-tone,.icon-music-tone-alt,.icon-mustache,.icon-note,.icon-notebook,.icon-options,.icon-options-vertical,.icon-organization,.icon-paper-clip,.icon-paper-plane,.icon-paypal,.icon-pencil,.icon-people,.icon-phone,.icon-picture,.icon-pie-chart,.icon-pin,.icon-plane,.icon-playlist,.icon-plus,.icon-power,.icon-present,.icon-printer,.icon-puzzle,.icon-question,.icon-refresh,.icon-reload,.icon-rocket,.icon-screen-desktop,.icon-screen-smartphone,.icon-screen-tablet,.icon-settings,.icon-share,.icon-share-alt,.icon-shield,.icon-shuffle,.icon-size-actual,.icon-size-fullscreen,.icon-social-behance,.icon-social-dribbble,.icon-social-dropbox,.icon-social-facebook,.icon-social-foursqare,.icon-social-github,.icon-social-google,.icon-social-instagram,.icon-social-linkedin,.icon-social-pinterest,.icon-social-reddit,.icon-social-skype,.icon-social-soundcloud,.icon-social-spotify,.icon-social-steam,.icon-social-stumbleupon,.icon-social-tumblr,.icon-social-twitter,.icon-social-vkontakte,.icon-social-youtube,.icon-speech,.icon-speedometer,.icon-star,.icon-support,.icon-symbol-female,.icon-symbol-male,.icon-tag,.icon-target,.icon-trash,.icon-trophy,.icon-umbrella,.icon-user,.icon-user-female,.icon-user-follow,.icon-user-following,.icon-user-unfollow,.icon-vector,.icon-volume-1,.icon-volume-2,.icon-volume-off,.icon-wallet,.icon-wrench{font-family:simple-line-icons;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-user:before{content:"\e005"}.icon-people:before{content:"\e001"}.icon-user-female:before{content:"\e000"}.icon-user-follow:before{content:"\e002"}.icon-user-following:before{content:"\e003"}.icon-user-unfollow:before{content:"\e004"}.icon-login:before{content:"\e066"}.icon-logout:before{content:"\e065"}.icon-emotsmile:before{content:"\e021"}.icon-phone:before{content:"\e600"}.icon-call-end:before{content:"\e048"}.icon-call-in:before{content:"\e047"}.icon-call-out:before{content:"\e046"}.icon-map:before{content:"\e033"}.icon-location-pin:before{content:"\e096"}.icon-direction:before{content:"\e042"}.icon-directions:before{content:"\e041"}.icon-compass:before{content:"\e045"}.icon-layers:before{content:"\e034"}.icon-menu:before{content:"\e601"}.icon-list:before{content:"\e067"}.icon-options-vertical:before{content:"\e602"}.icon-options:before{content:"\e603"}.icon-arrow-down:before{content:"\e604"}.icon-arrow-left:before{content:"\e605"}.icon-arrow-right:before{content:"\e606"}.icon-arrow-up:before{content:"\e607"}.icon-arrow-up-circle:before{content:"\e078"}.icon-arrow-left-circle:before{content:"\e07a"}.icon-arrow-right-circle:before{content:"\e079"}.icon-arrow-down-circle:before{content:"\e07b"}.icon-check:before{content:"\e080"}.icon-clock:before{content:"\e081"}.icon-plus:before{content:"\e095"}.icon-minus:before{content:"\e615"}.icon-close:before{content:"\e082"}.icon-event:before{content:"\e619"}.icon-exclamation:before{content:"\e617"}.icon-organization:before{content:"\e616"}.icon-trophy:before{content:"\e006"}.icon-screen-smartphone:before{content:"\e010"}.icon-screen-desktop:before{content:"\e011"}.icon-plane:before{content:"\e012"}.icon-notebook:before{content:"\e013"}.icon-mustache:before{content:"\e014"}.icon-mouse:before{content:"\e015"}.icon-magnet:before{content:"\e016"}.icon-energy:before{content:"\e020"}.icon-disc:before{content:"\e022"}.icon-cursor:before{content:"\e06e"}.icon-cursor-move:before{content:"\e023"}.icon-crop:before{content:"\e024"}.icon-chemistry:before{content:"\e026"}.icon-speedometer:before{content:"\e007"}.icon-shield:before{content:"\e00e"}.icon-screen-tablet:before{content:"\e00f"}.icon-magic-wand:before{content:"\e017"}.icon-hourglass:before{content:"\e018"}.icon-graduation:before{content:"\e019"}.icon-ghost:before{content:"\e01a"}.icon-game-controller:before{content:"\e01b"}.icon-fire:before{content:"\e01c"}.icon-eyeglass:before{content:"\e01d"}.icon-envelope-open:before{content:"\e01e"}.icon-envelope-letter:before{content:"\e01f"}.icon-bell:before{content:"\e027"}.icon-badge:before{content:"\e028"}.icon-anchor:before{content:"\e029"}.icon-wallet:before{content:"\e02a"}.icon-vector:before{content:"\e02b"}.icon-speech:before{content:"\e02c"}.icon-puzzle:before{content:"\e02d"}.icon-printer:before{content:"\e02e"}.icon-present:before{content:"\e02f"}.icon-playlist:before{content:"\e030"}.icon-pin:before{content:"\e031"}.icon-picture:before{content:"\e032"}.icon-handbag:before{content:"\e035"}.icon-globe-alt:before{content:"\e036"}.icon-globe:before{content:"\e037"}.icon-folder-alt:before{content:"\e039"}.icon-folder:before{content:"\e089"}.icon-film:before{content:"\e03a"}.icon-feed:before{content:"\e03b"}.icon-drop:before{content:"\e03e"}.icon-drawer:before{content:"\e03f"}.icon-docs:before{content:"\e040"}.icon-doc:before{content:"\e085"}.icon-diamond:before{content:"\e043"}.icon-cup:before{content:"\e044"}.icon-calculator:before{content:"\e049"}.icon-bubbles:before{content:"\e04a"}.icon-briefcase:before{content:"\e04b"}.icon-book-open:before{content:"\e04c"}.icon-basket-loaded:before{content:"\e04d"}.icon-basket:before{content:"\e04e"}.icon-bag:before{content:"\e04f"}.icon-action-undo:before{content:"\e050"}.icon-action-redo:before{content:"\e051"}.icon-wrench:before{content:"\e052"}.icon-umbrella:before{content:"\e053"}.icon-trash:before{content:"\e054"}.icon-tag:before{content:"\e055"}.icon-support:before{content:"\e056"}.icon-frame:before{content:"\e038"}.icon-size-fullscreen:before{content:"\e057"}.icon-size-actual:before{content:"\e058"}.icon-shuffle:before{content:"\e059"}.icon-share-alt:before{content:"\e05a"}.icon-share:before{content:"\e05b"}.icon-rocket:before{content:"\e05c"}.icon-question:before{content:"\e05d"}.icon-pie-chart:before{content:"\e05e"}.icon-pencil:before{content:"\e05f"}.icon-note:before{content:"\e060"}.icon-loop:before{content:"\e064"}.icon-home:before{content:"\e069"}.icon-grid:before{content:"\e06a"}.icon-graph:before{content:"\e06b"}.icon-microphone:before{content:"\e063"}.icon-music-tone-alt:before{content:"\e061"}.icon-music-tone:before{content:"\e062"}.icon-earphones-alt:before{content:"\e03c"}.icon-earphones:before{content:"\e03d"}.icon-equalizer:before{content:"\e06c"}.icon-like:before{content:"\e068"}.icon-dislike:before{content:"\e06d"}.icon-control-start:before{content:"\e06f"}.icon-control-rewind:before{content:"\e070"}.icon-control-play:before{content:"\e071"}.icon-control-pause:before{content:"\e072"}.icon-control-forward:before{content:"\e073"}.icon-control-end:before{content:"\e074"}.icon-volume-1:before{content:"\e09f"}.icon-volume-2:before{content:"\e0a0"}.icon-volume-off:before{content:"\e0a1"}.icon-calendar:before{content:"\e075"}.icon-bulb:before{content:"\e076"}.icon-chart:before{content:"\e077"}.icon-ban:before{content:"\e07c"}.icon-bubble:before{content:"\e07d"}.icon-camrecorder:before{content:"\e07e"}.icon-camera:before{content:"\e07f"}.icon-cloud-download:before{content:"\e083"}.icon-cloud-upload:before{content:"\e084"}.icon-envelope:before{content:"\e086"}.icon-eye:before{content:"\e087"}.icon-flag:before{content:"\e088"}.icon-heart:before{content:"\e08a"}.icon-info:before{content:"\e08b"}.icon-key:before{content:"\e08c"}.icon-link:before{content:"\e08d"}.icon-lock:before{content:"\e08e"}.icon-lock-open:before{content:"\e08f"}.icon-magnifier:before{content:"\e090"}.icon-magnifier-add:before{content:"\e091"}.icon-magnifier-remove:before{content:"\e092"}.icon-paper-clip:before{content:"\e093"}.icon-paper-plane:before{content:"\e094"}.icon-power:before{content:"\e097"}.icon-refresh:before{content:"\e098"}.icon-reload:before{content:"\e099"}.icon-settings:before{content:"\e09a"}.icon-star:before{content:"\e09b"}.icon-symbol-female:before{content:"\e09c"}.icon-symbol-male:before{content:"\e09d"}.icon-target:before{content:"\e09e"}.icon-credit-card:before{content:"\e025"}.icon-paypal:before{content:"\e608"}.icon-social-tumblr:before{content:"\e00a"}.icon-social-twitter:before{content:"\e009"}.icon-social-facebook:before{content:"\e00b"}.icon-social-instagram:before{content:"\e609"}.icon-social-linkedin:before{content:"\e60a"}.icon-social-pinterest:before{content:"\e60b"}.icon-social-github:before{content:"\e60c"}.icon-social-google:before{content:"\e60d"}.icon-social-reddit:before{content:"\e60e"}.icon-social-skype:before{content:"\e60f"}.icon-social-dribbble:before{content:"\e00d"}.icon-social-behance:before{content:"\e610"}.icon-social-foursqare:before{content:"\e611"}.icon-social-soundcloud:before{content:"\e612"}.icon-social-spotify:before{content:"\e613"}.icon-social-stumbleupon:before{content:"\e614"}.icon-social-youtube:before{content:"\e008"}.icon-social-dropbox:before{content:"\e00c"}.icon-social-vkontakte:before{content:"\e618"}.icon-social-steam:before{content:"\e620"} \ No newline at end of file diff --git a/static/kevin-master/assets/js/RTCMultiConnection.js b/static/kevin-master/assets/js/RTCMultiConnection.js deleted file mode 100644 index 5d4ffd9..0000000 --- a/static/kevin-master/assets/js/RTCMultiConnection.js +++ /dev/null @@ -1,5856 +0,0 @@ -'use strict'; - -// Last time updated: 2020-12-21 6:32:02 AM UTC - -// _________________________ -// RTCMultiConnection v3.7.0 - -// Open-Sourced: https://github.com/muaz-khan/RTCMultiConnection - -// -------------------------------------------------- -// Muaz Khan - www.MuazKhan.com -// MIT License - www.WebRTC-Experiment.com/licence -// -------------------------------------------------- - -var RTCMultiConnection = function(roomid, forceOptions) { - - var browserFakeUserAgent = 'Fake/5.0 (FakeOS) AppleWebKit/123 (KHTML, like Gecko) Fake/12.3.4567.89 Fake/123.45'; - - (function(that) { - if (!that) { - return; - } - - if (typeof window !== 'undefined') { - return; - } - - if (typeof global === 'undefined') { - return; - } - - global.navigator = { - userAgent: browserFakeUserAgent, - getUserMedia: function() {} - }; - - if (!global.console) { - global.console = {}; - } - - if (typeof global.console.debug === 'undefined') { - global.console.debug = global.console.info = global.console.error = global.console.log = global.console.log || function() { - console.log(arguments); - }; - } - - if (typeof document === 'undefined') { - /*global document:true */ - that.document = {}; - - document.createElement = document.captureStream = document.mozCaptureStream = function() { - var obj = { - getContext: function() { - return obj; - }, - play: function() {}, - pause: function() {}, - drawImage: function() {}, - toDataURL: function() { - return ''; - } - }; - return obj; - }; - - document.addEventListener = document.removeEventListener = that.addEventListener = that.removeEventListener = function() {}; - - that.HTMLVideoElement = that.HTMLMediaElement = function() {}; - } - - if (typeof io === 'undefined') { - that.io = function() { - return { - on: function(eventName, callback) { - callback = callback || function() {}; - - if (eventName === 'connect') { - callback(); - } - }, - emit: function(eventName, data, callback) { - callback = callback || function() {}; - if (eventName === 'open-room' || eventName === 'join-room') { - callback(true, data.sessionid, null); - } - } - }; - }; - } - - if (typeof location === 'undefined') { - /*global location:true */ - that.location = { - protocol: 'file:', - href: '', - hash: '', - origin: 'self' - }; - } - - if (typeof screen === 'undefined') { - /*global screen:true */ - that.screen = { - width: 0, - height: 0 - }; - } - - if (typeof URL === 'undefined') { - /*global screen:true */ - that.URL = { - createObjectURL: function() { - return ''; - }, - revokeObjectURL: function() { - return ''; - } - }; - } - - /*global window:true */ - that.window = global; - })(typeof global !== 'undefined' ? global : null); - - function SocketConnection(connection, connectCallback) { - function isData(session) { - return !session.audio && !session.video && !session.screen && session.data; - } - - var parameters = ''; - - parameters += '?userid=' + connection.userid; - parameters += '&sessionid=' + connection.sessionid; - parameters += '&msgEvent=' + connection.socketMessageEvent; - parameters += '&socketCustomEvent=' + connection.socketCustomEvent; - parameters += '&autoCloseEntireSession=' + !!connection.autoCloseEntireSession; - - if (connection.session.broadcast === true) { - parameters += '&oneToMany=true'; - } - - parameters += '&maxParticipantsAllowed=' + connection.maxParticipantsAllowed; - - if (connection.enableScalableBroadcast) { - parameters += '&enableScalableBroadcast=true'; - parameters += '&maxRelayLimitPerUser=' + (connection.maxRelayLimitPerUser || 2); - } - - parameters += '&extra=' + JSON.stringify(connection.extra || {}); - - if (connection.socketCustomParameters) { - parameters += connection.socketCustomParameters; - } - - try { - io.sockets = {}; - } catch (e) {}; - - if (!connection.socketURL) { - connection.socketURL = '/'; - } - - if (connection.socketURL.substr(connection.socketURL.length - 1, 1) != '/') { - // connection.socketURL = 'https://domain.com:9001/'; - throw '"socketURL" MUST end with a slash.'; - } - - if (connection.enableLogs) { - if (connection.socketURL == '/') { - console.info('socket.io url is: ', location.origin + '/'); - } else { - console.info('socket.io url is: ', connection.socketURL); - } - } - - try { - connection.socket = io(connection.socketURL + parameters); - } catch (e) { - connection.socket = io.connect(connection.socketURL + parameters, connection.socketOptions); - } - - var mPeer = connection.multiPeersHandler; - - connection.socket.on('extra-data-updated', function(remoteUserId, extra) { - if (!connection.peers[remoteUserId]) return; - connection.peers[remoteUserId].extra = extra; - - connection.onExtraDataUpdated({ - userid: remoteUserId, - extra: extra - }); - - updateExtraBackup(remoteUserId, extra); - }); - - function updateExtraBackup(remoteUserId, extra) { - if (!connection.peersBackup[remoteUserId]) { - connection.peersBackup[remoteUserId] = { - userid: remoteUserId, - extra: {} - }; - } - - connection.peersBackup[remoteUserId].extra = extra; - } - - function onMessageEvent(message) { - if (message.remoteUserId != connection.userid) return; - - if (connection.peers[message.sender] && connection.peers[message.sender].extra != message.message.extra) { - connection.peers[message.sender].extra = message.extra; - connection.onExtraDataUpdated({ - userid: message.sender, - extra: message.extra - }); - - updateExtraBackup(message.sender, message.extra); - } - - if (message.message.streamSyncNeeded && connection.peers[message.sender]) { - var stream = connection.streamEvents[message.message.streamid]; - if (!stream || !stream.stream) { - return; - } - - var action = message.message.action; - - if (action === 'ended' || action === 'inactive' || action === 'stream-removed') { - if (connection.peersBackup[stream.userid]) { - stream.extra = connection.peersBackup[stream.userid].extra; - } - connection.onstreamended(stream); - return; - } - - var type = message.message.type != 'both' ? message.message.type : null; - - if (typeof stream.stream[action] == 'function') { - stream.stream[action](type); - } - return; - } - - if (message.message === 'dropPeerConnection') { - connection.deletePeer(message.sender); - return; - } - - if (message.message.allParticipants) { - if (message.message.allParticipants.indexOf(message.sender) === -1) { - message.message.allParticipants.push(message.sender); - } - - message.message.allParticipants.forEach(function(participant) { - mPeer[!connection.peers[participant] ? 'createNewPeer' : 'renegotiatePeer'](participant, { - localPeerSdpConstraints: { - OfferToReceiveAudio: connection.sdpConstraints.mandatory.OfferToReceiveAudio, - OfferToReceiveVideo: connection.sdpConstraints.mandatory.OfferToReceiveVideo - }, - remotePeerSdpConstraints: { - OfferToReceiveAudio: connection.session.oneway ? !!connection.session.audio : connection.sdpConstraints.mandatory.OfferToReceiveAudio, - OfferToReceiveVideo: connection.session.oneway ? !!connection.session.video || !!connection.session.screen : connection.sdpConstraints.mandatory.OfferToReceiveVideo - }, - isOneWay: !!connection.session.oneway || connection.direction === 'one-way', - isDataOnly: isData(connection.session) - }); - }); - return; - } - - if (message.message.newParticipant) { - if (message.message.newParticipant == connection.userid) return; - if (!!connection.peers[message.message.newParticipant]) return; - - mPeer.createNewPeer(message.message.newParticipant, message.message.userPreferences || { - localPeerSdpConstraints: { - OfferToReceiveAudio: connection.sdpConstraints.mandatory.OfferToReceiveAudio, - OfferToReceiveVideo: connection.sdpConstraints.mandatory.OfferToReceiveVideo - }, - remotePeerSdpConstraints: { - OfferToReceiveAudio: connection.session.oneway ? !!connection.session.audio : connection.sdpConstraints.mandatory.OfferToReceiveAudio, - OfferToReceiveVideo: connection.session.oneway ? !!connection.session.video || !!connection.session.screen : connection.sdpConstraints.mandatory.OfferToReceiveVideo - }, - isOneWay: !!connection.session.oneway || connection.direction === 'one-way', - isDataOnly: isData(connection.session) - }); - return; - } - - if (message.message.readyForOffer) { - if (connection.attachStreams.length) { - connection.waitingForLocalMedia = false; - } - - if (connection.waitingForLocalMedia) { - // if someone is waiting to join you - // make sure that we've local media before making a handshake - setTimeout(function() { - onMessageEvent(message); - }, 1); - return; - } - } - - if (message.message.newParticipationRequest && message.sender !== connection.userid) { - if (connection.peers[message.sender]) { - connection.deletePeer(message.sender); - } - - var userPreferences = { - extra: message.extra || {}, - localPeerSdpConstraints: message.message.remotePeerSdpConstraints || { - OfferToReceiveAudio: connection.sdpConstraints.mandatory.OfferToReceiveAudio, - OfferToReceiveVideo: connection.sdpConstraints.mandatory.OfferToReceiveVideo - }, - remotePeerSdpConstraints: message.message.localPeerSdpConstraints || { - OfferToReceiveAudio: connection.session.oneway ? !!connection.session.audio : connection.sdpConstraints.mandatory.OfferToReceiveAudio, - OfferToReceiveVideo: connection.session.oneway ? !!connection.session.video || !!connection.session.screen : connection.sdpConstraints.mandatory.OfferToReceiveVideo - }, - isOneWay: typeof message.message.isOneWay !== 'undefined' ? message.message.isOneWay : !!connection.session.oneway || connection.direction === 'one-way', - isDataOnly: typeof message.message.isDataOnly !== 'undefined' ? message.message.isDataOnly : isData(connection.session), - dontGetRemoteStream: typeof message.message.isOneWay !== 'undefined' ? message.message.isOneWay : !!connection.session.oneway || connection.direction === 'one-way', - dontAttachLocalStream: !!message.message.dontGetRemoteStream, - connectionDescription: message, - successCallback: function() {} - }; - - connection.onNewParticipant(message.sender, userPreferences); - return; - } - - if (message.message.changedUUID) { - if (connection.peers[message.message.oldUUID]) { - connection.peers[message.message.newUUID] = connection.peers[message.message.oldUUID]; - delete connection.peers[message.message.oldUUID]; - } - } - - if (message.message.userLeft) { - mPeer.onUserLeft(message.sender); - - if (!!message.message.autoCloseEntireSession) { - connection.leave(); - } - - return; - } - - mPeer.addNegotiatedMessage(message.message, message.sender); - } - - connection.socket.on(connection.socketMessageEvent, onMessageEvent); - - var alreadyConnected = false; - - connection.socket.resetProps = function() { - alreadyConnected = false; - }; - - connection.socket.on('connect', function() { - if (alreadyConnected) { - return; - } - alreadyConnected = true; - - if (connection.enableLogs) { - console.info('socket.io connection is opened.'); - } - - setTimeout(function() { - connection.socket.emit('extra-data-updated', connection.extra); - }, 1000); - - if (connectCallback) { - connectCallback(connection.socket); - } - }); - - connection.socket.on('disconnect', function(event) { - connection.onSocketDisconnect(event); - }); - - connection.socket.on('error', function(event) { - connection.onSocketError(event); - }); - - connection.socket.on('user-disconnected', function(remoteUserId) { - if (remoteUserId === connection.userid) { - return; - } - - connection.onUserStatusChanged({ - userid: remoteUserId, - status: 'offline', - extra: connection.peers[remoteUserId] ? connection.peers[remoteUserId].extra || {} : {} - }); - - connection.deletePeer(remoteUserId); - }); - - connection.socket.on('user-connected', function(userid) { - if (userid === connection.userid) { - return; - } - - connection.onUserStatusChanged({ - userid: userid, - status: 'online', - extra: connection.peers[userid] ? connection.peers[userid].extra || {} : {} - }); - }); - - connection.socket.on('closed-entire-session', function(sessionid, extra) { - connection.leave(); - connection.onEntireSessionClosed({ - sessionid: sessionid, - userid: sessionid, - extra: extra - }); - }); - - connection.socket.on('userid-already-taken', function(useridAlreadyTaken, yourNewUserId) { - connection.onUserIdAlreadyTaken(useridAlreadyTaken, yourNewUserId); - }); - - connection.socket.on('logs', function(log) { - if (!connection.enableLogs) return; - console.debug('server-logs', log); - }); - - connection.socket.on('number-of-broadcast-viewers-updated', function(data) { - connection.onNumberOfBroadcastViewersUpdated(data); - }); - - connection.socket.on('set-isInitiator-true', function(sessionid) { - if (sessionid != connection.sessionid) return; - connection.isInitiator = true; - }); - } - - function MultiPeers(connection) { - var self = this; - - var skipPeers = ['getAllParticipants', 'getLength', 'selectFirst', 'streams', 'send', 'forEach']; - connection.peers = { - getLength: function() { - var numberOfPeers = 0; - for (var peer in this) { - if (skipPeers.indexOf(peer) == -1) { - numberOfPeers++; - } - } - return numberOfPeers; - }, - selectFirst: function() { - var firstPeer; - for (var peer in this) { - if (skipPeers.indexOf(peer) == -1) { - firstPeer = this[peer]; - } - } - return firstPeer; - }, - getAllParticipants: function(sender) { - var allPeers = []; - for (var peer in this) { - if (skipPeers.indexOf(peer) == -1 && peer != sender) { - allPeers.push(peer); - } - } - return allPeers; - }, - forEach: function(callback) { - this.getAllParticipants().forEach(function(participant) { - callback(connection.peers[participant]); - }); - }, - send: function(data, remoteUserId) { - var that = this; - - if (!isNull(data.size) && !isNull(data.type)) { - if (connection.enableFileSharing) { - self.shareFile(data, remoteUserId); - return; - } - - if (typeof data !== 'string') { - data = JSON.stringify(data); - } - } - - if (data.type !== 'text' && !(data instanceof ArrayBuffer) && !(data instanceof DataView)) { - TextSender.send({ - text: data, - channel: this, - connection: connection, - remoteUserId: remoteUserId - }); - return; - } - - if (data.type === 'text') { - data = JSON.stringify(data); - } - - if (remoteUserId) { - var remoteUser = connection.peers[remoteUserId]; - if (remoteUser) { - if (!remoteUser.channels.length) { - connection.peers[remoteUserId].createDataChannel(); - connection.renegotiate(remoteUserId); - setTimeout(function() { - that.send(data, remoteUserId); - }, 3000); - return; - } - - remoteUser.channels.forEach(function(channel) { - channel.send(data); - }); - return; - } - } - - this.getAllParticipants().forEach(function(participant) { - if (!that[participant].channels.length) { - connection.peers[participant].createDataChannel(); - connection.renegotiate(participant); - setTimeout(function() { - that[participant].channels.forEach(function(channel) { - channel.send(data); - }); - }, 3000); - return; - } - - that[participant].channels.forEach(function(channel) { - channel.send(data); - }); - }); - } - }; - - this.uuid = connection.userid; - - this.getLocalConfig = function(remoteSdp, remoteUserId, userPreferences) { - if (!userPreferences) { - userPreferences = {}; - } - - return { - streamsToShare: userPreferences.streamsToShare || {}, - rtcMultiConnection: connection, - connectionDescription: userPreferences.connectionDescription, - userid: remoteUserId, - localPeerSdpConstraints: userPreferences.localPeerSdpConstraints, - remotePeerSdpConstraints: userPreferences.remotePeerSdpConstraints, - dontGetRemoteStream: !!userPreferences.dontGetRemoteStream, - dontAttachLocalStream: !!userPreferences.dontAttachLocalStream, - renegotiatingPeer: !!userPreferences.renegotiatingPeer, - peerRef: userPreferences.peerRef, - channels: userPreferences.channels || [], - onLocalSdp: function(localSdp) { - self.onNegotiationNeeded(localSdp, remoteUserId); - }, - onLocalCandidate: function(localCandidate) { - localCandidate = OnIceCandidateHandler.processCandidates(connection, localCandidate) - if (localCandidate) { - self.onNegotiationNeeded(localCandidate, remoteUserId); - } - }, - remoteSdp: remoteSdp, - onDataChannelMessage: function(message) { - if (!connection.fbr && connection.enableFileSharing) initFileBufferReader(); - - if (typeof message == 'string' || !connection.enableFileSharing) { - self.onDataChannelMessage(message, remoteUserId); - return; - } - - var that = this; - - if (message instanceof ArrayBuffer || message instanceof DataView) { - connection.fbr.convertToObject(message, function(object) { - that.onDataChannelMessage(object); - }); - return; - } - - if (message.readyForNextChunk) { - connection.fbr.getNextChunk(message, function(nextChunk, isLastChunk) { - connection.peers[remoteUserId].channels.forEach(function(channel) { - channel.send(nextChunk); - }); - }, remoteUserId); - return; - } - - if (message.chunkMissing) { - connection.fbr.chunkMissing(message); - return; - } - - connection.fbr.addChunk(message, function(promptNextChunk) { - connection.peers[remoteUserId].peer.channel.send(promptNextChunk); - }); - }, - onDataChannelError: function(error) { - self.onDataChannelError(error, remoteUserId); - }, - onDataChannelOpened: function(channel) { - self.onDataChannelOpened(channel, remoteUserId); - }, - onDataChannelClosed: function(event) { - self.onDataChannelClosed(event, remoteUserId); - }, - onRemoteStream: function(stream) { - if (connection.peers[remoteUserId]) { - connection.peers[remoteUserId].streams.push(stream); - } - - self.onGettingRemoteMedia(stream, remoteUserId); - }, - onRemoteStreamRemoved: function(stream) { - self.onRemovingRemoteMedia(stream, remoteUserId); - }, - onPeerStateChanged: function(states) { - self.onPeerStateChanged(states); - - if (states.iceConnectionState === 'new') { - self.onNegotiationStarted(remoteUserId, states); - } - - if (states.iceConnectionState === 'connected') { - self.onNegotiationCompleted(remoteUserId, states); - } - - if (states.iceConnectionState.search(/closed|failed/gi) !== -1) { - self.onUserLeft(remoteUserId); - self.disconnectWith(remoteUserId); - } - } - }; - }; - - this.createNewPeer = function(remoteUserId, userPreferences) { - if (connection.maxParticipantsAllowed <= connection.getAllParticipants().length) { - return; - } - - userPreferences = userPreferences || {}; - - if (connection.isInitiator && !!connection.session.audio && connection.session.audio === 'two-way' && !userPreferences.streamsToShare) { - userPreferences.isOneWay = false; - userPreferences.isDataOnly = false; - userPreferences.session = connection.session; - } - - if (!userPreferences.isOneWay && !userPreferences.isDataOnly) { - userPreferences.isOneWay = true; - this.onNegotiationNeeded({ - enableMedia: true, - userPreferences: userPreferences - }, remoteUserId); - return; - } - - userPreferences = connection.setUserPreferences(userPreferences, remoteUserId); - var localConfig = this.getLocalConfig(null, remoteUserId, userPreferences); - connection.peers[remoteUserId] = new PeerInitiator(localConfig); - }; - - this.createAnsweringPeer = function(remoteSdp, remoteUserId, userPreferences) { - userPreferences = connection.setUserPreferences(userPreferences || {}, remoteUserId); - - var localConfig = this.getLocalConfig(remoteSdp, remoteUserId, userPreferences); - connection.peers[remoteUserId] = new PeerInitiator(localConfig); - }; - - this.renegotiatePeer = function(remoteUserId, userPreferences, remoteSdp) { - if (!connection.peers[remoteUserId]) { - if (connection.enableLogs) { - console.error('Peer (' + remoteUserId + ') does not exist. Renegotiation skipped.'); - } - return; - } - - if (!userPreferences) { - userPreferences = {}; - } - - userPreferences.renegotiatingPeer = true; - userPreferences.peerRef = connection.peers[remoteUserId].peer; - userPreferences.channels = connection.peers[remoteUserId].channels; - - var localConfig = this.getLocalConfig(remoteSdp, remoteUserId, userPreferences); - - connection.peers[remoteUserId] = new PeerInitiator(localConfig); - }; - - this.replaceTrack = function(track, remoteUserId, isVideoTrack) { - if (!connection.peers[remoteUserId]) { - throw 'This peer (' + remoteUserId + ') does not exist.'; - } - - var peer = connection.peers[remoteUserId].peer; - - if (!!peer.getSenders && typeof peer.getSenders === 'function' && peer.getSenders().length) { - peer.getSenders().forEach(function(rtpSender) { - if (isVideoTrack && rtpSender.track.kind === 'video') { - connection.peers[remoteUserId].peer.lastVideoTrack = rtpSender.track; - rtpSender.replaceTrack(track); - } - - if (!isVideoTrack && rtpSender.track.kind === 'audio') { - connection.peers[remoteUserId].peer.lastAudioTrack = rtpSender.track; - rtpSender.replaceTrack(track); - } - }); - return; - } - - console.warn('RTPSender.replaceTrack is NOT supported.'); - this.renegotiatePeer(remoteUserId); - }; - - this.onNegotiationNeeded = function(message, remoteUserId) {}; - this.addNegotiatedMessage = function(message, remoteUserId) { - if (message.type && message.sdp) { - if (message.type == 'answer') { - if (connection.peers[remoteUserId]) { - connection.peers[remoteUserId].addRemoteSdp(message); - } - } - - if (message.type == 'offer') { - if (message.renegotiatingPeer) { - this.renegotiatePeer(remoteUserId, null, message); - } else { - this.createAnsweringPeer(message, remoteUserId); - } - } - - if (connection.enableLogs) { - console.log('Remote peer\'s sdp:', message.sdp); - } - return; - } - - if (message.candidate) { - if (connection.peers[remoteUserId]) { - connection.peers[remoteUserId].addRemoteCandidate(message); - } - - if (connection.enableLogs) { - console.log('Remote peer\'s candidate pairs:', message.candidate); - } - return; - } - - if (message.enableMedia) { - connection.session = message.userPreferences.session || connection.session; - - if (connection.session.oneway && connection.attachStreams.length) { - connection.attachStreams = []; - } - - if (message.userPreferences.isDataOnly && connection.attachStreams.length) { - connection.attachStreams.length = []; - } - - var streamsToShare = {}; - connection.attachStreams.forEach(function(stream) { - streamsToShare[stream.streamid] = { - isAudio: !!stream.isAudio, - isVideo: !!stream.isVideo, - isScreen: !!stream.isScreen - }; - }); - message.userPreferences.streamsToShare = streamsToShare; - - self.onNegotiationNeeded({ - readyForOffer: true, - userPreferences: message.userPreferences - }, remoteUserId); - } - - if (message.readyForOffer) { - connection.onReadyForOffer(remoteUserId, message.userPreferences); - } - - function cb(stream) { - gumCallback(stream, message, remoteUserId); - } - }; - - function gumCallback(stream, message, remoteUserId) { - var streamsToShare = {}; - connection.attachStreams.forEach(function(stream) { - streamsToShare[stream.streamid] = { - isAudio: !!stream.isAudio, - isVideo: !!stream.isVideo, - isScreen: !!stream.isScreen - }; - }); - message.userPreferences.streamsToShare = streamsToShare; - - self.onNegotiationNeeded({ - readyForOffer: true, - userPreferences: message.userPreferences - }, remoteUserId); - } - - this.onGettingRemoteMedia = function(stream, remoteUserId) {}; - this.onRemovingRemoteMedia = function(stream, remoteUserId) {}; - this.onGettingLocalMedia = function(localStream) {}; - this.onLocalMediaError = function(error, constraints) { - connection.onMediaError(error, constraints); - }; - - function initFileBufferReader() { - connection.fbr = new FileBufferReader(); - connection.fbr.onProgress = function(chunk) { - connection.onFileProgress(chunk); - }; - connection.fbr.onBegin = function(file) { - connection.onFileStart(file); - }; - connection.fbr.onEnd = function(file) { - connection.onFileEnd(file); - }; - } - - this.shareFile = function(file, remoteUserId) { - initFileBufferReader(); - - connection.fbr.readAsArrayBuffer(file, function(uuid) { - var arrayOfUsers = connection.getAllParticipants(); - - if (remoteUserId) { - arrayOfUsers = [remoteUserId]; - } - - arrayOfUsers.forEach(function(participant) { - connection.fbr.getNextChunk(uuid, function(nextChunk) { - connection.peers[participant].channels.forEach(function(channel) { - channel.send(nextChunk); - }); - }, participant); - }); - }, { - userid: connection.userid, - // extra: connection.extra, - chunkSize: DetectRTC.browser.name === 'Firefox' ? 15 * 1000 : connection.chunkSize || 0 - }); - }; - - if (typeof 'TextReceiver' !== 'undefined') { - var textReceiver = new TextReceiver(connection); - } - - this.onDataChannelMessage = function(message, remoteUserId) { - textReceiver.receive(JSON.parse(message), remoteUserId, connection.peers[remoteUserId] ? connection.peers[remoteUserId].extra : {}); - }; - - this.onDataChannelClosed = function(event, remoteUserId) { - event.userid = remoteUserId; - event.extra = connection.peers[remoteUserId] ? connection.peers[remoteUserId].extra : {}; - connection.onclose(event); - }; - - this.onDataChannelError = function(error, remoteUserId) { - error.userid = remoteUserId; - event.extra = connection.peers[remoteUserId] ? connection.peers[remoteUserId].extra : {}; - connection.onerror(error); - }; - - this.onDataChannelOpened = function(channel, remoteUserId) { - // keep last channel only; we are not expecting parallel/channels channels - if (connection.peers[remoteUserId].channels.length) { - connection.peers[remoteUserId].channels = [channel]; - return; - } - - connection.peers[remoteUserId].channels.push(channel); - connection.onopen({ - userid: remoteUserId, - extra: connection.peers[remoteUserId] ? connection.peers[remoteUserId].extra : {}, - channel: channel - }); - }; - - this.onPeerStateChanged = function(state) { - connection.onPeerStateChanged(state); - }; - - this.onNegotiationStarted = function(remoteUserId, states) {}; - this.onNegotiationCompleted = function(remoteUserId, states) {}; - - this.getRemoteStreams = function(remoteUserId) { - remoteUserId = remoteUserId || connection.peers.getAllParticipants()[0]; - return connection.peers[remoteUserId] ? connection.peers[remoteUserId].streams : []; - }; - } - - 'use strict'; - - // Last Updated On: 2020-08-12 11:18:41 AM UTC - - // ________________ - // DetectRTC v1.4.1 - - // Open-Sourced: https://github.com/muaz-khan/DetectRTC - - // -------------------------------------------------- - // Muaz Khan - www.MuazKhan.com - // MIT License - www.WebRTC-Experiment.com/licence - // -------------------------------------------------- - - (function() { - - var browserFakeUserAgent = 'Fake/5.0 (FakeOS) AppleWebKit/123 (KHTML, like Gecko) Fake/12.3.4567.89 Fake/123.45'; - - var isNodejs = typeof process === 'object' && typeof process.versions === 'object' && process.versions.node && /*node-process*/ !process.browser; - if (isNodejs) { - var version = process.versions.node.toString().replace('v', ''); - browserFakeUserAgent = 'Nodejs/' + version + ' (NodeOS) AppleWebKit/' + version + ' (KHTML, like Gecko) Nodejs/' + version + ' Nodejs/' + version - } - - (function(that) { - if (typeof window !== 'undefined') { - return; - } - - if (typeof window === 'undefined' && typeof global !== 'undefined') { - global.navigator = { - userAgent: browserFakeUserAgent, - getUserMedia: function() {} - }; - - /*global window:true */ - that.window = global; - } else if (typeof window === 'undefined') { - // window = this; - } - - if (typeof location === 'undefined') { - /*global location:true */ - that.location = { - protocol: 'file:', - href: '', - hash: '' - }; - } - - if (typeof screen === 'undefined') { - /*global screen:true */ - that.screen = { - width: 0, - height: 0 - }; - } - })(typeof global !== 'undefined' ? global : window); - - /*global navigator:true */ - var navigator = window.navigator; - - if (typeof navigator !== 'undefined') { - if (typeof navigator.webkitGetUserMedia !== 'undefined') { - navigator.getUserMedia = navigator.webkitGetUserMedia; - } - - if (typeof navigator.mozGetUserMedia !== 'undefined') { - navigator.getUserMedia = navigator.mozGetUserMedia; - } - } else { - navigator = { - getUserMedia: function() {}, - userAgent: browserFakeUserAgent - }; - } - - var isMobileDevice = !!(/Android|webOS|iPhone|iPad|iPod|BB10|BlackBerry|IEMobile|Opera Mini|Mobile|mobile/i.test(navigator.userAgent || '')); - - var isEdge = navigator.userAgent.indexOf('Edge') !== -1 && (!!navigator.msSaveOrOpenBlob || !!navigator.msSaveBlob); - - var isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0; - var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && ('netscape' in window) && / rv:/.test(navigator.userAgent); - var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); - var isChrome = !!window.chrome && !isOpera; - var isIE = typeof document !== 'undefined' && !!document.documentMode && !isEdge; - - // this one can also be used: - // https://www.websocket.org/js/stuff.js (DetectBrowser.js) - - function getBrowserInfo() { - var nVer = navigator.appVersion; - var nAgt = navigator.userAgent; - var browserName = navigator.appName; - var fullVersion = '' + parseFloat(navigator.appVersion); - var majorVersion = parseInt(navigator.appVersion, 10); - var nameOffset, verOffset, ix; - - // In Opera, the true version is after 'Opera' or after 'Version' - if (isOpera) { - browserName = 'Opera'; - try { - fullVersion = navigator.userAgent.split('OPR/')[1].split(' ')[0]; - majorVersion = fullVersion.split('.')[0]; - } catch (e) { - fullVersion = '0.0.0.0'; - majorVersion = 0; - } - } - // In MSIE version <=10, the true version is after 'MSIE' in userAgent - // In IE 11, look for the string after 'rv:' - else if (isIE) { - verOffset = nAgt.indexOf('rv:'); - if (verOffset > 0) { //IE 11 - fullVersion = nAgt.substring(verOffset + 3); - } else { //IE 10 or earlier - verOffset = nAgt.indexOf('MSIE'); - fullVersion = nAgt.substring(verOffset + 5); - } - browserName = 'IE'; - } - // In Chrome, the true version is after 'Chrome' - else if (isChrome) { - verOffset = nAgt.indexOf('Chrome'); - browserName = 'Chrome'; - fullVersion = nAgt.substring(verOffset + 7); - } - // In Safari, the true version is after 'Safari' or after 'Version' - else if (isSafari) { - // both and safri and chrome has same userAgent - if (nAgt.indexOf('CriOS') !== -1) { - verOffset = nAgt.indexOf('CriOS'); - browserName = 'Chrome'; - fullVersion = nAgt.substring(verOffset + 6); - } else if (nAgt.indexOf('FxiOS') !== -1) { - verOffset = nAgt.indexOf('FxiOS'); - browserName = 'Firefox'; - fullVersion = nAgt.substring(verOffset + 6); - } else { - verOffset = nAgt.indexOf('Safari'); - - browserName = 'Safari'; - fullVersion = nAgt.substring(verOffset + 7); - - if ((verOffset = nAgt.indexOf('Version')) !== -1) { - fullVersion = nAgt.substring(verOffset + 8); - } - - if (navigator.userAgent.indexOf('Version/') !== -1) { - fullVersion = navigator.userAgent.split('Version/')[1].split(' ')[0]; - } - } - } - // In Firefox, the true version is after 'Firefox' - else if (isFirefox) { - verOffset = nAgt.indexOf('Firefox'); - browserName = 'Firefox'; - fullVersion = nAgt.substring(verOffset + 8); - } - - // In most other browsers, 'name/version' is at the end of userAgent - else if ((nameOffset = nAgt.lastIndexOf(' ') + 1) < (verOffset = nAgt.lastIndexOf('/'))) { - browserName = nAgt.substring(nameOffset, verOffset); - fullVersion = nAgt.substring(verOffset + 1); - - if (browserName.toLowerCase() === browserName.toUpperCase()) { - browserName = navigator.appName; - } - } - - if (isEdge) { - browserName = 'Edge'; - fullVersion = navigator.userAgent.split('Edge/')[1]; - // fullVersion = parseInt(navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)[2], 10).toString(); - } - - // trim the fullVersion string at semicolon/space/bracket if present - if ((ix = fullVersion.search(/[; \)]/)) !== -1) { - fullVersion = fullVersion.substring(0, ix); - } - - majorVersion = parseInt('' + fullVersion, 10); - - if (isNaN(majorVersion)) { - fullVersion = '' + parseFloat(navigator.appVersion); - majorVersion = parseInt(navigator.appVersion, 10); - } - - return { - fullVersion: fullVersion, - version: majorVersion, - name: browserName, - isPrivateBrowsing: false - }; - } - - // via: https://gist.github.com/cou929/7973956 - - function retry(isDone, next) { - var currentTrial = 0, - maxRetry = 50, - interval = 10, - isTimeout = false; - var id = window.setInterval( - function() { - if (isDone()) { - window.clearInterval(id); - next(isTimeout); - } - if (currentTrial++ > maxRetry) { - window.clearInterval(id); - isTimeout = true; - next(isTimeout); - } - }, - 10 - ); - } - - function isIE10OrLater(userAgent) { - var ua = userAgent.toLowerCase(); - if (ua.indexOf('msie') === 0 && ua.indexOf('trident') === 0) { - return false; - } - var match = /(?:msie|rv:)\s?([\d\.]+)/.exec(ua); - if (match && parseInt(match[1], 10) >= 10) { - return true; - } - return false; - } - - function detectPrivateMode(callback) { - var isPrivate; - - try { - - if (window.webkitRequestFileSystem) { - window.webkitRequestFileSystem( - window.TEMPORARY, 1, - function() { - isPrivate = false; - }, - function(e) { - isPrivate = true; - } - ); - } else if (window.indexedDB && /Firefox/.test(window.navigator.userAgent)) { - var db; - try { - db = window.indexedDB.open('test'); - db.onerror = function() { - return true; - }; - } catch (e) { - isPrivate = true; - } - - if (typeof isPrivate === 'undefined') { - retry( - function isDone() { - return db.readyState === 'done' ? true : false; - }, - function next(isTimeout) { - if (!isTimeout) { - isPrivate = db.result ? false : true; - } - } - ); - } - } else if (isIE10OrLater(window.navigator.userAgent)) { - isPrivate = false; - try { - if (!window.indexedDB) { - isPrivate = true; - } - } catch (e) { - isPrivate = true; - } - } else if (window.localStorage && /Safari/.test(window.navigator.userAgent)) { - try { - window.localStorage.setItem('test', 1); - } catch (e) { - isPrivate = true; - } - - if (typeof isPrivate === 'undefined') { - isPrivate = false; - window.localStorage.removeItem('test'); - } - } - - } catch (e) { - isPrivate = false; - } - - retry( - function isDone() { - return typeof isPrivate !== 'undefined' ? true : false; - }, - function next(isTimeout) { - callback(isPrivate); - } - ); - } - - var isMobile = { - Android: function() { - return navigator.userAgent.match(/Android/i); - }, - BlackBerry: function() { - return navigator.userAgent.match(/BlackBerry|BB10/i); - }, - iOS: function() { - return navigator.userAgent.match(/iPhone|iPad|iPod/i); - }, - Opera: function() { - return navigator.userAgent.match(/Opera Mini/i); - }, - Windows: function() { - return navigator.userAgent.match(/IEMobile/i); - }, - any: function() { - return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows()); - }, - getOsName: function() { - var osName = 'Unknown OS'; - if (isMobile.Android()) { - osName = 'Android'; - } - - if (isMobile.BlackBerry()) { - osName = 'BlackBerry'; - } - - if (isMobile.iOS()) { - osName = 'iOS'; - } - - if (isMobile.Opera()) { - osName = 'Opera Mini'; - } - - if (isMobile.Windows()) { - osName = 'Windows'; - } - - return osName; - } - }; - - // via: http://jsfiddle.net/ChristianL/AVyND/ - function detectDesktopOS() { - var unknown = '-'; - - var nVer = navigator.appVersion; - var nAgt = navigator.userAgent; - - var os = unknown; - var clientStrings = [{ - s: 'Chrome OS', - r: /CrOS/ - }, { - s: 'Windows 10', - r: /(Windows 10.0|Windows NT 10.0)/ - }, { - s: 'Windows 8.1', - r: /(Windows 8.1|Windows NT 6.3)/ - }, { - s: 'Windows 8', - r: /(Windows 8|Windows NT 6.2)/ - }, { - s: 'Windows 7', - r: /(Windows 7|Windows NT 6.1)/ - }, { - s: 'Windows Vista', - r: /Windows NT 6.0/ - }, { - s: 'Windows Server 2003', - r: /Windows NT 5.2/ - }, { - s: 'Windows XP', - r: /(Windows NT 5.1|Windows XP)/ - }, { - s: 'Windows 2000', - r: /(Windows NT 5.0|Windows 2000)/ - }, { - s: 'Windows ME', - r: /(Win 9x 4.90|Windows ME)/ - }, { - s: 'Windows 98', - r: /(Windows 98|Win98)/ - }, { - s: 'Windows 95', - r: /(Windows 95|Win95|Windows_95)/ - }, { - s: 'Windows NT 4.0', - r: /(Windows NT 4.0|WinNT4.0|WinNT|Windows NT)/ - }, { - s: 'Windows CE', - r: /Windows CE/ - }, { - s: 'Windows 3.11', - r: /Win16/ - }, { - s: 'Android', - r: /Android/ - }, { - s: 'Open BSD', - r: /OpenBSD/ - }, { - s: 'Sun OS', - r: /SunOS/ - }, { - s: 'Linux', - r: /(Linux|X11)/ - }, { - s: 'iOS', - r: /(iPhone|iPad|iPod)/ - }, { - s: 'Mac OS X', - r: /Mac OS X/ - }, { - s: 'Mac OS', - r: /(MacPPC|MacIntel|Mac_PowerPC|Macintosh)/ - }, { - s: 'QNX', - r: /QNX/ - }, { - s: 'UNIX', - r: /UNIX/ - }, { - s: 'BeOS', - r: /BeOS/ - }, { - s: 'OS/2', - r: /OS\/2/ - }, { - s: 'Search Bot', - r: /(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver)/ - }]; - for (var i = 0, cs; cs = clientStrings[i]; i++) { - if (cs.r.test(nAgt)) { - os = cs.s; - break; - } - } - - var osVersion = unknown; - - if (/Windows/.test(os)) { - if (/Windows (.*)/.test(os)) { - osVersion = /Windows (.*)/.exec(os)[1]; - } - os = 'Windows'; - } - - switch (os) { - case 'Mac OS X': - if (/Mac OS X (10[\.\_\d]+)/.test(nAgt)) { - osVersion = /Mac OS X (10[\.\_\d]+)/.exec(nAgt)[1]; - } - break; - case 'Android': - if (/Android ([\.\_\d]+)/.test(nAgt)) { - osVersion = /Android ([\.\_\d]+)/.exec(nAgt)[1]; - } - break; - case 'iOS': - if (/OS (\d+)_(\d+)_?(\d+)?/.test(nAgt)) { - osVersion = /OS (\d+)_(\d+)_?(\d+)?/.exec(nVer); - if (osVersion && osVersion.length > 3) { - osVersion = osVersion[1] + '.' + osVersion[2] + '.' + (osVersion[3] | 0); - } - } - break; - } - - return { - osName: os, - osVersion: osVersion - }; - } - - var osName = 'Unknown OS'; - var osVersion = 'Unknown OS Version'; - - function getAndroidVersion(ua) { - ua = (ua || navigator.userAgent).toLowerCase(); - var match = ua.match(/android\s([0-9\.]*)/); - return match ? match[1] : false; - } - - var osInfo = detectDesktopOS(); - - if (osInfo && osInfo.osName && osInfo.osName != '-') { - osName = osInfo.osName; - osVersion = osInfo.osVersion; - } else if (isMobile.any()) { - osName = isMobile.getOsName(); - - if (osName == 'Android') { - osVersion = getAndroidVersion(); - } - } - - var isNodejs = typeof process === 'object' && typeof process.versions === 'object' && process.versions.node; - - if (osName === 'Unknown OS' && isNodejs) { - osName = 'Nodejs'; - osVersion = process.versions.node.toString().replace('v', ''); - } - - var isCanvasSupportsStreamCapturing = false; - var isVideoSupportsStreamCapturing = false; - ['captureStream', 'mozCaptureStream', 'webkitCaptureStream'].forEach(function(item) { - if (typeof document === 'undefined' || typeof document.createElement !== 'function') { - return; - } - - if (!isCanvasSupportsStreamCapturing && item in document.createElement('canvas')) { - isCanvasSupportsStreamCapturing = true; - } - - if (!isVideoSupportsStreamCapturing && item in document.createElement('video')) { - isVideoSupportsStreamCapturing = true; - } - }); - - var regexIpv4Local = /^(192\.168\.|169\.254\.|10\.|172\.(1[6-9]|2\d|3[01]))/, - regexIpv4 = /([0-9]{1,3}(\.[0-9]{1,3}){3})/, - regexIpv6 = /[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7}/; - - // via: https://github.com/diafygi/webrtc-ips - function DetectLocalIPAddress(callback, stream) { - if (!DetectRTC.isWebRTCSupported) { - return; - } - - var isPublic = true, - isIpv4 = true; - getIPs(function(ip) { - if (!ip) { - callback(); // Pass nothing to tell that ICE-gathering-ended - } else if (ip.match(regexIpv4Local)) { - isPublic = false; - callback('Local: ' + ip, isPublic, isIpv4); - } else if (ip.match(regexIpv6)) { //via https://ourcodeworld.com/articles/read/257/how-to-get-the-client-ip-address-with-javascript-only - isIpv4 = false; - callback('Public: ' + ip, isPublic, isIpv4); - } else { - callback('Public: ' + ip, isPublic, isIpv4); - } - }, stream); - } - - function getIPs(callback, stream) { - if (typeof document === 'undefined' || typeof document.getElementById !== 'function') { - return; - } - - var ipDuplicates = {}; - - var RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection; - - if (!RTCPeerConnection) { - var iframe = document.getElementById('iframe'); - if (!iframe) { - return; - } - var win = iframe.contentWindow; - RTCPeerConnection = win.RTCPeerConnection || win.mozRTCPeerConnection || win.webkitRTCPeerConnection; - } - - if (!RTCPeerConnection) { - return; - } - - var peerConfig = null; - - if (DetectRTC.browser === 'Chrome' && DetectRTC.browser.version < 58) { - // todo: add support for older Opera - peerConfig = { - optional: [{ - RtpDataChannels: true - }] - }; - } - - var servers = { - iceServers: [{ - urls: 'stun:stun.l.google.com:19302' - }] - }; - - var pc = new RTCPeerConnection(servers, peerConfig); - - if (stream) { - if (pc.addStream) { - pc.addStream(stream); - } else if (pc.addTrack && stream.getTracks()[0]) { - pc.addTrack(stream.getTracks()[0], stream); - } - } - - function handleCandidate(candidate) { - if (!candidate) { - callback(); // Pass nothing to tell that ICE-gathering-ended - return; - } - - var match = regexIpv4.exec(candidate); - if (!match) { - return; - } - var ipAddress = match[1]; - var isPublic = (candidate.match(regexIpv4Local)), - isIpv4 = true; - - if (ipDuplicates[ipAddress] === undefined) { - callback(ipAddress, isPublic, isIpv4); - } - - ipDuplicates[ipAddress] = true; - } - - // listen for candidate events - pc.onicecandidate = function(event) { - if (event.candidate && event.candidate.candidate) { - handleCandidate(event.candidate.candidate); - } else { - handleCandidate(); // Pass nothing to tell that ICE-gathering-ended - } - }; - - // create data channel - if (!stream) { - try { - pc.createDataChannel('sctp', {}); - } catch (e) {} - } - - // create an offer sdp - if (DetectRTC.isPromisesSupported) { - pc.createOffer().then(function(result) { - pc.setLocalDescription(result).then(afterCreateOffer); - }); - } else { - pc.createOffer(function(result) { - pc.setLocalDescription(result, afterCreateOffer, function() {}); - }, function() {}); - } - - function afterCreateOffer() { - var lines = pc.localDescription.sdp.split('\n'); - - lines.forEach(function(line) { - if (line && line.indexOf('a=candidate:') === 0) { - handleCandidate(line); - } - }); - } - } - - var MediaDevices = []; - - var audioInputDevices = []; - var audioOutputDevices = []; - var videoInputDevices = []; - - if (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) { - // Firefox 38+ seems having support of enumerateDevices - // Thanks @xdumaine/enumerateDevices - navigator.enumerateDevices = function(callback) { - var enumerateDevices = navigator.mediaDevices.enumerateDevices(); - if (enumerateDevices && enumerateDevices.then) { - navigator.mediaDevices.enumerateDevices().then(callback).catch(function() { - callback([]); - }); - } else { - callback([]); - } - }; - } - - // Media Devices detection - var canEnumerate = false; - - /*global MediaStreamTrack:true */ - if (typeof MediaStreamTrack !== 'undefined' && 'getSources' in MediaStreamTrack) { - canEnumerate = true; - } else if (navigator.mediaDevices && !!navigator.mediaDevices.enumerateDevices) { - canEnumerate = true; - } - - var hasMicrophone = false; - var hasSpeakers = false; - var hasWebcam = false; - - var isWebsiteHasMicrophonePermissions = false; - var isWebsiteHasWebcamPermissions = false; - - // http://dev.w3.org/2011/webrtc/editor/getusermedia.html#mediadevices - function checkDeviceSupport(callback) { - if (!canEnumerate) { - if (callback) { - callback(); - } - return; - } - - if (!navigator.enumerateDevices && window.MediaStreamTrack && window.MediaStreamTrack.getSources) { - navigator.enumerateDevices = window.MediaStreamTrack.getSources.bind(window.MediaStreamTrack); - } - - if (!navigator.enumerateDevices && navigator.enumerateDevices) { - navigator.enumerateDevices = navigator.enumerateDevices.bind(navigator); - } - - if (!navigator.enumerateDevices) { - if (callback) { - callback(); - } - return; - } - - MediaDevices = []; - - audioInputDevices = []; - audioOutputDevices = []; - videoInputDevices = []; - - hasMicrophone = false; - hasSpeakers = false; - hasWebcam = false; - - isWebsiteHasMicrophonePermissions = false; - isWebsiteHasWebcamPermissions = false; - - // to prevent duplication - var alreadyUsedDevices = {}; - - navigator.enumerateDevices(function(devices) { - MediaDevices = []; - - audioInputDevices = []; - audioOutputDevices = []; - videoInputDevices = []; - - devices.forEach(function(_device) { - var device = {}; - for (var d in _device) { - try { - if (typeof _device[d] !== 'function') { - device[d] = _device[d]; - } - } catch (e) {} - } - - if (alreadyUsedDevices[device.deviceId + device.label + device.kind]) { - return; - } - - // if it is MediaStreamTrack.getSources - if (device.kind === 'audio') { - device.kind = 'audioinput'; - } - - if (device.kind === 'video') { - device.kind = 'videoinput'; - } - - if (!device.deviceId) { - device.deviceId = device.id; - } - - if (!device.id) { - device.id = device.deviceId; - } - - if (!device.label) { - device.isCustomLabel = true; - - if (device.kind === 'videoinput') { - device.label = 'Camera ' + (videoInputDevices.length + 1); - } else if (device.kind === 'audioinput') { - device.label = 'Microphone ' + (audioInputDevices.length + 1); - } else if (device.kind === 'audiooutput') { - device.label = 'Speaker ' + (audioOutputDevices.length + 1); - } else { - device.label = 'Please invoke getUserMedia once.'; - } - - if (typeof DetectRTC !== 'undefined' && DetectRTC.browser.isChrome && DetectRTC.browser.version >= 46 && !/^(https:|chrome-extension:)$/g.test(location.protocol || '')) { - if (typeof document !== 'undefined' && typeof document.domain === 'string' && document.domain.search && document.domain.search(/localhost|127.0./g) === -1) { - device.label = 'HTTPs is required to get label of this ' + device.kind + ' device.'; - } - } - } else { - // Firefox on Android still returns empty label - if (device.kind === 'videoinput' && !isWebsiteHasWebcamPermissions) { - isWebsiteHasWebcamPermissions = true; - } - - if (device.kind === 'audioinput' && !isWebsiteHasMicrophonePermissions) { - isWebsiteHasMicrophonePermissions = true; - } - } - - if (device.kind === 'audioinput') { - hasMicrophone = true; - - if (audioInputDevices.indexOf(device) === -1) { - audioInputDevices.push(device); - } - } - - if (device.kind === 'audiooutput') { - hasSpeakers = true; - - if (audioOutputDevices.indexOf(device) === -1) { - audioOutputDevices.push(device); - } - } - - if (device.kind === 'videoinput') { - hasWebcam = true; - - if (videoInputDevices.indexOf(device) === -1) { - videoInputDevices.push(device); - } - } - - // there is no 'videoouput' in the spec. - MediaDevices.push(device); - - alreadyUsedDevices[device.deviceId + device.label + device.kind] = device; - }); - - if (typeof DetectRTC !== 'undefined') { - // to sync latest outputs - DetectRTC.MediaDevices = MediaDevices; - DetectRTC.hasMicrophone = hasMicrophone; - DetectRTC.hasSpeakers = hasSpeakers; - DetectRTC.hasWebcam = hasWebcam; - - DetectRTC.isWebsiteHasWebcamPermissions = isWebsiteHasWebcamPermissions; - DetectRTC.isWebsiteHasMicrophonePermissions = isWebsiteHasMicrophonePermissions; - - DetectRTC.audioInputDevices = audioInputDevices; - DetectRTC.audioOutputDevices = audioOutputDevices; - DetectRTC.videoInputDevices = videoInputDevices; - } - - if (callback) { - callback(); - } - }); - } - - var DetectRTC = window.DetectRTC || {}; - - // ---------- - // DetectRTC.browser.name || DetectRTC.browser.version || DetectRTC.browser.fullVersion - DetectRTC.browser = getBrowserInfo(); - - detectPrivateMode(function(isPrivateBrowsing) { - DetectRTC.browser.isPrivateBrowsing = !!isPrivateBrowsing; - }); - - // DetectRTC.isChrome || DetectRTC.isFirefox || DetectRTC.isEdge - DetectRTC.browser['is' + DetectRTC.browser.name] = true; - - // ----------- - DetectRTC.osName = osName; - DetectRTC.osVersion = osVersion; - - var isNodeWebkit = typeof process === 'object' && typeof process.versions === 'object' && process.versions['node-webkit']; - - // --------- Detect if system supports WebRTC 1.0 or WebRTC 1.1. - var isWebRTCSupported = false; - ['RTCPeerConnection', 'webkitRTCPeerConnection', 'mozRTCPeerConnection', 'RTCIceGatherer'].forEach(function(item) { - if (isWebRTCSupported) { - return; - } - - if (item in window) { - isWebRTCSupported = true; - } - }); - DetectRTC.isWebRTCSupported = isWebRTCSupported; - - //------- - DetectRTC.isORTCSupported = typeof RTCIceGatherer !== 'undefined'; - - // --------- Detect if system supports screen capturing API - var isScreenCapturingSupported = false; - if (DetectRTC.browser.isChrome && DetectRTC.browser.version >= 35) { - isScreenCapturingSupported = true; - } else if (DetectRTC.browser.isFirefox && DetectRTC.browser.version >= 34) { - isScreenCapturingSupported = true; - } else if (DetectRTC.browser.isEdge && DetectRTC.browser.version >= 17) { - isScreenCapturingSupported = true; - } else if (DetectRTC.osName === 'Android' && DetectRTC.browser.isChrome) { - isScreenCapturingSupported = true; - } - - if (!!navigator.getDisplayMedia || (navigator.mediaDevices && navigator.mediaDevices.getDisplayMedia)) { - isScreenCapturingSupported = true; - } - - if (!/^(https:|chrome-extension:)$/g.test(location.protocol || '')) { - var isNonLocalHost = typeof document !== 'undefined' && typeof document.domain === 'string' && document.domain.search && document.domain.search(/localhost|127.0./g) === -1; - if (isNonLocalHost && (DetectRTC.browser.isChrome || DetectRTC.browser.isEdge || DetectRTC.browser.isOpera)) { - isScreenCapturingSupported = false; - } else if (DetectRTC.browser.isFirefox) { - isScreenCapturingSupported = false; - } - } - DetectRTC.isScreenCapturingSupported = isScreenCapturingSupported; - - // --------- Detect if WebAudio API are supported - var webAudio = { - isSupported: false, - isCreateMediaStreamSourceSupported: false - }; - - ['AudioContext', 'webkitAudioContext', 'mozAudioContext', 'msAudioContext'].forEach(function(item) { - if (webAudio.isSupported) { - return; - } - - if (item in window) { - webAudio.isSupported = true; - - if (window[item] && 'createMediaStreamSource' in window[item].prototype) { - webAudio.isCreateMediaStreamSourceSupported = true; - } - } - }); - DetectRTC.isAudioContextSupported = webAudio.isSupported; - DetectRTC.isCreateMediaStreamSourceSupported = webAudio.isCreateMediaStreamSourceSupported; - - // ---------- Detect if SCTP/RTP channels are supported. - - var isRtpDataChannelsSupported = false; - if (DetectRTC.browser.isChrome && DetectRTC.browser.version > 31) { - isRtpDataChannelsSupported = true; - } - DetectRTC.isRtpDataChannelsSupported = isRtpDataChannelsSupported; - - var isSCTPSupportd = false; - if (DetectRTC.browser.isFirefox && DetectRTC.browser.version > 28) { - isSCTPSupportd = true; - } else if (DetectRTC.browser.isChrome && DetectRTC.browser.version > 25) { - isSCTPSupportd = true; - } else if (DetectRTC.browser.isOpera && DetectRTC.browser.version >= 11) { - isSCTPSupportd = true; - } - DetectRTC.isSctpDataChannelsSupported = isSCTPSupportd; - - // --------- - - DetectRTC.isMobileDevice = isMobileDevice; // "isMobileDevice" boolean is defined in "getBrowserInfo.js" - - // ------ - var isGetUserMediaSupported = false; - if (navigator.getUserMedia) { - isGetUserMediaSupported = true; - } else if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { - isGetUserMediaSupported = true; - } - - if (DetectRTC.browser.isChrome && DetectRTC.browser.version >= 46 && !/^(https:|chrome-extension:)$/g.test(location.protocol || '')) { - if (typeof document !== 'undefined' && typeof document.domain === 'string' && document.domain.search && document.domain.search(/localhost|127.0./g) === -1) { - isGetUserMediaSupported = 'Requires HTTPs'; - } - } - - if (DetectRTC.osName === 'Nodejs') { - isGetUserMediaSupported = false; - } - DetectRTC.isGetUserMediaSupported = isGetUserMediaSupported; - - var displayResolution = ''; - if (screen.width) { - var width = (screen.width) ? screen.width : ''; - var height = (screen.height) ? screen.height : ''; - displayResolution += '' + width + ' x ' + height; - } - DetectRTC.displayResolution = displayResolution; - - function getAspectRatio(w, h) { - function gcd(a, b) { - return (b == 0) ? a : gcd(b, a % b); - } - var r = gcd(w, h); - return (w / r) / (h / r); - } - - DetectRTC.displayAspectRatio = getAspectRatio(screen.width, screen.height).toFixed(2); - - // ---------- - DetectRTC.isCanvasSupportsStreamCapturing = isCanvasSupportsStreamCapturing; - DetectRTC.isVideoSupportsStreamCapturing = isVideoSupportsStreamCapturing; - - if (DetectRTC.browser.name == 'Chrome' && DetectRTC.browser.version >= 53) { - if (!DetectRTC.isCanvasSupportsStreamCapturing) { - DetectRTC.isCanvasSupportsStreamCapturing = 'Requires chrome flag: enable-experimental-web-platform-features'; - } - - if (!DetectRTC.isVideoSupportsStreamCapturing) { - DetectRTC.isVideoSupportsStreamCapturing = 'Requires chrome flag: enable-experimental-web-platform-features'; - } - } - - // ------ - DetectRTC.DetectLocalIPAddress = DetectLocalIPAddress; - - DetectRTC.isWebSocketsSupported = 'WebSocket' in window && 2 === window.WebSocket.CLOSING; - DetectRTC.isWebSocketsBlocked = !DetectRTC.isWebSocketsSupported; - - if (DetectRTC.osName === 'Nodejs') { - DetectRTC.isWebSocketsSupported = true; - DetectRTC.isWebSocketsBlocked = false; - } - - DetectRTC.checkWebSocketsSupport = function(callback) { - callback = callback || function() {}; - try { - var starttime; - var websocket = new WebSocket('wss://echo.websocket.org:443/'); - websocket.onopen = function() { - DetectRTC.isWebSocketsBlocked = false; - starttime = (new Date).getTime(); - websocket.send('ping'); - }; - websocket.onmessage = function() { - DetectRTC.WebsocketLatency = (new Date).getTime() - starttime + 'ms'; - callback(); - websocket.close(); - websocket = null; - }; - websocket.onerror = function() { - DetectRTC.isWebSocketsBlocked = true; - callback(); - }; - } catch (e) { - DetectRTC.isWebSocketsBlocked = true; - callback(); - } - }; - - // ------- - DetectRTC.load = function(callback) { - callback = callback || function() {}; - checkDeviceSupport(callback); - }; - - // check for microphone/camera support! - if (typeof checkDeviceSupport === 'function') { - // checkDeviceSupport(); - } - - if (typeof MediaDevices !== 'undefined') { - DetectRTC.MediaDevices = MediaDevices; - } else { - DetectRTC.MediaDevices = []; - } - - DetectRTC.hasMicrophone = hasMicrophone; - DetectRTC.hasSpeakers = hasSpeakers; - DetectRTC.hasWebcam = hasWebcam; - - DetectRTC.isWebsiteHasWebcamPermissions = isWebsiteHasWebcamPermissions; - DetectRTC.isWebsiteHasMicrophonePermissions = isWebsiteHasMicrophonePermissions; - - DetectRTC.audioInputDevices = audioInputDevices; - DetectRTC.audioOutputDevices = audioOutputDevices; - DetectRTC.videoInputDevices = videoInputDevices; - - // ------ - var isSetSinkIdSupported = false; - if (typeof document !== 'undefined' && typeof document.createElement === 'function' && 'setSinkId' in document.createElement('video')) { - isSetSinkIdSupported = true; - } - DetectRTC.isSetSinkIdSupported = isSetSinkIdSupported; - - // ----- - var isRTPSenderReplaceTracksSupported = false; - if (DetectRTC.browser.isFirefox && typeof mozRTCPeerConnection !== 'undefined' /*&& DetectRTC.browser.version > 39*/ ) { - /*global mozRTCPeerConnection:true */ - if ('getSenders' in mozRTCPeerConnection.prototype) { - isRTPSenderReplaceTracksSupported = true; - } - } else if (DetectRTC.browser.isChrome && typeof webkitRTCPeerConnection !== 'undefined') { - /*global webkitRTCPeerConnection:true */ - if ('getSenders' in webkitRTCPeerConnection.prototype) { - isRTPSenderReplaceTracksSupported = true; - } - } - DetectRTC.isRTPSenderReplaceTracksSupported = isRTPSenderReplaceTracksSupported; - - //------ - var isRemoteStreamProcessingSupported = false; - if (DetectRTC.browser.isFirefox && DetectRTC.browser.version > 38) { - isRemoteStreamProcessingSupported = true; - } - DetectRTC.isRemoteStreamProcessingSupported = isRemoteStreamProcessingSupported; - - //------- - var isApplyConstraintsSupported = false; - - /*global MediaStreamTrack:true */ - if (typeof MediaStreamTrack !== 'undefined' && 'applyConstraints' in MediaStreamTrack.prototype) { - isApplyConstraintsSupported = true; - } - DetectRTC.isApplyConstraintsSupported = isApplyConstraintsSupported; - - //------- - var isMultiMonitorScreenCapturingSupported = false; - if (DetectRTC.browser.isFirefox && DetectRTC.browser.version >= 43) { - // version 43 merely supports platforms for multi-monitors - // version 44 will support exact multi-monitor selection i.e. you can select any monitor for screen capturing. - isMultiMonitorScreenCapturingSupported = true; - } - DetectRTC.isMultiMonitorScreenCapturingSupported = isMultiMonitorScreenCapturingSupported; - - DetectRTC.isPromisesSupported = !!('Promise' in window); - - // version is generated by "grunt" - DetectRTC.version = '1.4.1'; - - if (typeof DetectRTC === 'undefined') { - window.DetectRTC = {}; - } - - var MediaStream = window.MediaStream; - - if (typeof MediaStream === 'undefined' && typeof webkitMediaStream !== 'undefined') { - MediaStream = webkitMediaStream; - } - - if (typeof MediaStream !== 'undefined' && typeof MediaStream === 'function') { - DetectRTC.MediaStream = Object.keys(MediaStream.prototype); - } else DetectRTC.MediaStream = false; - - if (typeof MediaStreamTrack !== 'undefined') { - DetectRTC.MediaStreamTrack = Object.keys(MediaStreamTrack.prototype); - } else DetectRTC.MediaStreamTrack = false; - - var RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection; - - if (typeof RTCPeerConnection !== 'undefined') { - DetectRTC.RTCPeerConnection = Object.keys(RTCPeerConnection.prototype); - } else DetectRTC.RTCPeerConnection = false; - - window.DetectRTC = DetectRTC; - - if (typeof module !== 'undefined' /* && !!module.exports*/ ) { - module.exports = DetectRTC; - } - - if (typeof define === 'function' && define.amd) { - define('DetectRTC', [], function() { - return DetectRTC; - }); - } - })(); - - // globals.js - - if (typeof cordova !== 'undefined') { - DetectRTC.isMobileDevice = true; - DetectRTC.browser.name = 'Chrome'; - } - - if (navigator && navigator.userAgent && navigator.userAgent.indexOf('Crosswalk') !== -1) { - DetectRTC.isMobileDevice = true; - DetectRTC.browser.name = 'Chrome'; - } - - function fireEvent(obj, eventName, args) { - if (typeof CustomEvent === 'undefined') { - return; - } - - var eventDetail = { - arguments: args, - __exposedProps__: args - }; - - var event = new CustomEvent(eventName, eventDetail); - obj.dispatchEvent(event); - } - - function setHarkEvents(connection, streamEvent) { - if (!streamEvent.stream || !getTracks(streamEvent.stream, 'audio').length) return; - - if (!connection || !streamEvent) { - throw 'Both arguments are required.'; - } - - if (!connection.onspeaking || !connection.onsilence) { - return; - } - - if (typeof hark === 'undefined') { - throw 'hark.js not found.'; - } - - hark(streamEvent.stream, { - onspeaking: function() { - connection.onspeaking(streamEvent); - }, - onsilence: function() { - connection.onsilence(streamEvent); - }, - onvolumechange: function(volume, threshold) { - if (!connection.onvolumechange) { - return; - } - connection.onvolumechange(merge({ - volume: volume, - threshold: threshold - }, streamEvent)); - } - }); - } - - function setMuteHandlers(connection, streamEvent) { - if (!streamEvent.stream || !streamEvent.stream || !streamEvent.stream.addEventListener) return; - - streamEvent.stream.addEventListener('mute', function(event) { - event = connection.streamEvents[streamEvent.streamid]; - - event.session = { - audio: event.muteType === 'audio', - video: event.muteType === 'video' - }; - - connection.onmute(event); - }, false); - - streamEvent.stream.addEventListener('unmute', function(event) { - event = connection.streamEvents[streamEvent.streamid]; - - event.session = { - audio: event.unmuteType === 'audio', - video: event.unmuteType === 'video' - }; - - connection.onunmute(event); - }, false); - } - - function getRandomString() { - if (window.crypto && window.crypto.getRandomValues && navigator.userAgent.indexOf('Safari') === -1) { - var a = window.crypto.getRandomValues(new Uint32Array(3)), - token = ''; - for (var i = 0, l = a.length; i < l; i++) { - token += a[i].toString(36); - } - return token; - } else { - return (Math.random() * new Date().getTime()).toString(36).replace(/\./g, ''); - } - } - - // Get HTMLAudioElement/HTMLVideoElement accordingly - // todo: add API documentation for connection.autoCreateMediaElement - - function getRMCMediaElement(stream, callback, connection) { - if (!connection.autoCreateMediaElement) { - callback({}); - return; - } - - var isAudioOnly = false; - if (!getTracks(stream, 'video').length && !stream.isVideo && !stream.isScreen) { - isAudioOnly = true; - } - - if (DetectRTC.browser.name === 'Firefox') { - if (connection.session.video || connection.session.screen) { - isAudioOnly = false; - } - } - - var mediaElement = document.createElement(isAudioOnly ? 'audio' : 'video'); - - mediaElement.srcObject = stream; - - mediaElement.setAttribute('autoplay', true); - mediaElement.setAttribute('playsinline', true); - mediaElement.setAttribute('controls', true); - mediaElement.setAttribute('muted', false); - mediaElement.setAttribute('volume', 1); - - // http://goo.gl/WZ5nFl - // Firefox don't yet support onended for any stream (remote/local) - if (DetectRTC.browser.name === 'Firefox') { - var streamEndedEvent = 'ended'; - - if ('oninactive' in mediaElement) { - streamEndedEvent = 'inactive'; - } - - mediaElement.addEventListener(streamEndedEvent, function() { - // fireEvent(stream, streamEndedEvent, stream); - currentUserMediaRequest.remove(stream.idInstance); - - if (stream.type === 'local') { - streamEndedEvent = 'ended'; - - if ('oninactive' in stream) { - streamEndedEvent = 'inactive'; - } - - StreamsHandler.onSyncNeeded(stream.streamid, streamEndedEvent); - - connection.attachStreams.forEach(function(aStream, idx) { - if (stream.streamid === aStream.streamid) { - delete connection.attachStreams[idx]; - } - }); - - var newStreamsArray = []; - connection.attachStreams.forEach(function(aStream) { - if (aStream) { - newStreamsArray.push(aStream); - } - }); - connection.attachStreams = newStreamsArray; - - var streamEvent = connection.streamEvents[stream.streamid]; - - if (streamEvent) { - connection.onstreamended(streamEvent); - return; - } - if (this.parentNode) { - this.parentNode.removeChild(this); - } - } - }, false); - } - - var played = mediaElement.play(); - if (typeof played !== 'undefined') { - var cbFired = false; - setTimeout(function() { - if (!cbFired) { - cbFired = true; - callback(mediaElement); - } - }, 1000); - played.then(function() { - if (cbFired) return; - cbFired = true; - callback(mediaElement); - }).catch(function(error) { - if (cbFired) return; - cbFired = true; - callback(mediaElement); - }); - } else { - callback(mediaElement); - } - } - - // if IE - if (!window.addEventListener) { - window.addEventListener = function(el, eventName, eventHandler) { - if (!el.attachEvent) { - return; - } - el.attachEvent('on' + eventName, eventHandler); - }; - } - - function listenEventHandler(eventName, eventHandler) { - window.removeEventListener(eventName, eventHandler); - window.addEventListener(eventName, eventHandler, false); - } - - window.attachEventListener = function(video, type, listener, useCapture) { - video.addEventListener(type, listener, useCapture); - }; - - function removeNullEntries(array) { - var newArray = []; - array.forEach(function(item) { - if (item) { - newArray.push(item); - } - }); - return newArray; - } - - - function isData(session) { - return !session.audio && !session.video && !session.screen && session.data; - } - - function isNull(obj) { - return typeof obj === 'undefined'; - } - - function isString(obj) { - return typeof obj === 'string'; - } - - var MediaStream = window.MediaStream; - - if (typeof MediaStream === 'undefined' && typeof webkitMediaStream !== 'undefined') { - MediaStream = webkitMediaStream; - } - - /*global MediaStream:true */ - if (typeof MediaStream !== 'undefined') { - if (!('stop' in MediaStream.prototype)) { - MediaStream.prototype.stop = function() { - this.getTracks().forEach(function(track) { - track.stop(); - }); - }; - } - } - - function isAudioPlusTab(connection, audioPlusTab) { - if (connection.session.audio && connection.session.audio === 'two-way') { - return false; - } - - if (DetectRTC.browser.name === 'Firefox' && audioPlusTab !== false) { - return true; - } - - if (DetectRTC.browser.name !== 'Chrome' || DetectRTC.browser.version < 50) return false; - - if (typeof audioPlusTab === true) { - return true; - } - - if (typeof audioPlusTab === 'undefined' && connection.session.audio && connection.session.screen && !connection.session.video) { - audioPlusTab = true; - return true; - } - - return false; - } - - function getAudioScreenConstraints(screen_constraints) { - if (DetectRTC.browser.name === 'Firefox') { - return true; - } - - if (DetectRTC.browser.name !== 'Chrome') return false; - - return { - mandatory: { - chromeMediaSource: screen_constraints.mandatory.chromeMediaSource, - chromeMediaSourceId: screen_constraints.mandatory.chromeMediaSourceId - } - }; - } - - window.iOSDefaultAudioOutputDevice = window.iOSDefaultAudioOutputDevice || 'speaker'; // earpiece or speaker - - function getTracks(stream, kind) { - if (!stream || !stream.getTracks) { - return []; - } - - return stream.getTracks().filter(function(t) { - return t.kind === (kind || 'audio'); - }); - } - - function isUnifiedPlanSupportedDefault() { - var canAddTransceiver = false; - - try { - if (typeof RTCRtpTransceiver === 'undefined') return false; - if (!('currentDirection' in RTCRtpTransceiver.prototype)) return false; - - var tempPc = new RTCPeerConnection(); - - try { - tempPc.addTransceiver('audio'); - canAddTransceiver = true; - } catch (e) {} - - tempPc.close(); - } catch (e) { - canAddTransceiver = false; - } - - return canAddTransceiver && isUnifiedPlanSuppored(); - } - - function isUnifiedPlanSuppored() { - var isUnifiedPlanSupported = false; - - try { - var pc = new RTCPeerConnection({ - sdpSemantics: 'unified-plan' - }); - - try { - var config = pc.getConfiguration(); - if (config.sdpSemantics == 'unified-plan') - isUnifiedPlanSupported = true; - else if (config.sdpSemantics == 'plan-b') - isUnifiedPlanSupported = false; - else - isUnifiedPlanSupported = false; - } catch (e) { - isUnifiedPlanSupported = false; - } - } catch (e) { - isUnifiedPlanSupported = false; - } - - return isUnifiedPlanSupported; - } - - // ios-hacks.js - - function setCordovaAPIs() { - // if (DetectRTC.osName !== 'iOS') return; - if (typeof cordova === 'undefined' || typeof cordova.plugins === 'undefined' || typeof cordova.plugins.iosrtc === 'undefined') return; - - var iosrtc = cordova.plugins.iosrtc; - window.webkitRTCPeerConnection = iosrtc.RTCPeerConnection; - window.RTCSessionDescription = iosrtc.RTCSessionDescription; - window.RTCIceCandidate = iosrtc.RTCIceCandidate; - window.MediaStream = iosrtc.MediaStream; - window.MediaStreamTrack = iosrtc.MediaStreamTrack; - navigator.getUserMedia = navigator.webkitGetUserMedia = iosrtc.getUserMedia; - - iosrtc.debug.enable('iosrtc*'); - if (typeof iosrtc.selectAudioOutput == 'function') { - iosrtc.selectAudioOutput(window.iOSDefaultAudioOutputDevice || 'speaker'); // earpiece or speaker - } - iosrtc.registerGlobals(); - } - - document.addEventListener('deviceready', setCordovaAPIs, false); - setCordovaAPIs(); - - // RTCPeerConnection.js - - var defaults = {}; - - function setSdpConstraints(config) { - var sdpConstraints = { - OfferToReceiveAudio: !!config.OfferToReceiveAudio, - OfferToReceiveVideo: !!config.OfferToReceiveVideo - }; - - return sdpConstraints; - } - - var RTCPeerConnection; - if (typeof window.RTCPeerConnection !== 'undefined') { - RTCPeerConnection = window.RTCPeerConnection; - } else if (typeof mozRTCPeerConnection !== 'undefined') { - RTCPeerConnection = mozRTCPeerConnection; - } else if (typeof webkitRTCPeerConnection !== 'undefined') { - RTCPeerConnection = webkitRTCPeerConnection; - } - - var RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription; - var RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate; - var MediaStreamTrack = window.MediaStreamTrack; - - function PeerInitiator(config) { - if (typeof window.RTCPeerConnection !== 'undefined') { - RTCPeerConnection = window.RTCPeerConnection; - } else if (typeof mozRTCPeerConnection !== 'undefined') { - RTCPeerConnection = mozRTCPeerConnection; - } else if (typeof webkitRTCPeerConnection !== 'undefined') { - RTCPeerConnection = webkitRTCPeerConnection; - } - - RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription; - RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate; - MediaStreamTrack = window.MediaStreamTrack; - - if (!RTCPeerConnection) { - throw 'WebRTC 1.0 (RTCPeerConnection) API are NOT available in this browser.'; - } - - var connection = config.rtcMultiConnection; - - this.extra = config.remoteSdp ? config.remoteSdp.extra : connection.extra; - this.userid = config.userid; - this.streams = []; - this.channels = config.channels || []; - this.connectionDescription = config.connectionDescription; - - this.addStream = function(session) { - connection.addStream(session, self.userid); - }; - - this.removeStream = function(streamid) { - connection.removeStream(streamid, self.userid); - }; - - var self = this; - - if (config.remoteSdp) { - this.connectionDescription = config.remoteSdp.connectionDescription; - } - - var allRemoteStreams = {}; - - defaults.sdpConstraints = setSdpConstraints({ - OfferToReceiveAudio: true, - OfferToReceiveVideo: true - }); - - var peer; - - var renegotiatingPeer = !!config.renegotiatingPeer; - if (config.remoteSdp) { - renegotiatingPeer = !!config.remoteSdp.renegotiatingPeer; - } - - var localStreams = []; - connection.attachStreams.forEach(function(stream) { - if (!!stream) { - localStreams.push(stream); - } - }); - - if (!renegotiatingPeer) { - var iceTransports = 'all'; - if (connection.candidates.turn || connection.candidates.relay) { - if (!connection.candidates.stun && !connection.candidates.reflexive && !connection.candidates.host) { - iceTransports = 'relay'; - } - } - - try { - // ref: developer.mozilla.org/en-US/docs/Web/API/RTCConfiguration - var params = { - iceServers: connection.iceServers, - iceTransportPolicy: connection.iceTransportPolicy || iceTransports - }; - - if (typeof connection.iceCandidatePoolSize !== 'undefined') { - params.iceCandidatePoolSize = connection.iceCandidatePoolSize; - } - - if (typeof connection.bundlePolicy !== 'undefined') { - params.bundlePolicy = connection.bundlePolicy; - } - - if (typeof connection.rtcpMuxPolicy !== 'undefined') { - params.rtcpMuxPolicy = connection.rtcpMuxPolicy; - } - - if (!!connection.sdpSemantics) { - params.sdpSemantics = connection.sdpSemantics || 'unified-plan'; - } - - if (!connection.iceServers || !connection.iceServers.length) { - params = null; - connection.optionalArgument = null; - } - - peer = new RTCPeerConnection(params, connection.optionalArgument); - } catch (e) { - try { - var params = { - iceServers: connection.iceServers - }; - - peer = new RTCPeerConnection(params); - } catch (e) { - peer = new RTCPeerConnection(); - } - } - } else { - peer = config.peerRef; - } - - if (!peer.getRemoteStreams && peer.getReceivers) { - peer.getRemoteStreams = function() { - var stream = new MediaStream(); - peer.getReceivers().forEach(function(receiver) { - stream.addTrack(receiver.track); - }); - return [stream]; - }; - } - - if (!peer.getLocalStreams && peer.getSenders) { - peer.getLocalStreams = function() { - var stream = new MediaStream(); - peer.getSenders().forEach(function(sender) { - stream.addTrack(sender.track); - }); - return [stream]; - }; - } - - peer.onicecandidate = function(event) { - if (!event.candidate) { - if (!connection.trickleIce) { - var localSdp = peer.localDescription; - config.onLocalSdp({ - type: localSdp.type, - sdp: localSdp.sdp, - remotePeerSdpConstraints: config.remotePeerSdpConstraints || false, - renegotiatingPeer: !!config.renegotiatingPeer || false, - connectionDescription: self.connectionDescription, - dontGetRemoteStream: !!config.dontGetRemoteStream, - extra: connection ? connection.extra : {}, - streamsToShare: streamsToShare - }); - } - return; - } - - if (!connection.trickleIce) return; - config.onLocalCandidate({ - candidate: event.candidate.candidate, - sdpMid: event.candidate.sdpMid, - sdpMLineIndex: event.candidate.sdpMLineIndex - }); - }; - - localStreams.forEach(function(localStream) { - if (config.remoteSdp && config.remoteSdp.remotePeerSdpConstraints && config.remoteSdp.remotePeerSdpConstraints.dontGetRemoteStream) { - return; - } - - if (config.dontAttachLocalStream) { - return; - } - - localStream = connection.beforeAddingStream(localStream, self); - - if (!localStream) return; - - peer.getLocalStreams().forEach(function(stream) { - if (localStream && stream.id == localStream.id) { - localStream = null; - } - }); - - if (localStream && localStream.getTracks) { - localStream.getTracks().forEach(function(track) { - try { - // last parameter is redundant for unified-plan - // starting from chrome version 72 - peer.addTrack(track, localStream); - } catch (e) {} - }); - } - }); - - peer.oniceconnectionstatechange = peer.onsignalingstatechange = function() { - var extra = self.extra; - if (connection.peers[self.userid]) { - extra = connection.peers[self.userid].extra || extra; - } - - if (!peer) { - return; - } - - config.onPeerStateChanged({ - iceConnectionState: peer.iceConnectionState, - iceGatheringState: peer.iceGatheringState, - signalingState: peer.signalingState, - extra: extra, - userid: self.userid - }); - - if (peer && peer.iceConnectionState && peer.iceConnectionState.search(/closed|failed/gi) !== -1 && self.streams instanceof Array) { - self.streams.forEach(function(stream) { - var streamEvent = connection.streamEvents[stream.id] || { - streamid: stream.id, - stream: stream, - type: 'remote' - }; - - connection.onstreamended(streamEvent); - }); - } - }; - - var sdpConstraints = { - OfferToReceiveAudio: !!localStreams.length, - OfferToReceiveVideo: !!localStreams.length - }; - - if (config.localPeerSdpConstraints) sdpConstraints = config.localPeerSdpConstraints; - - defaults.sdpConstraints = setSdpConstraints(sdpConstraints); - - var streamObject; - var dontDuplicate = {}; - - peer.ontrack = function(event) { - if (!event || event.type !== 'track') return; - - event.stream = event.streams[event.streams.length - 1]; - - if (!event.stream.id) { - event.stream.id = event.track.id; - } - - if (dontDuplicate[event.stream.id] && DetectRTC.browser.name !== 'Safari') { - if (event.track) { - event.track.onended = function() { // event.track.onmute = - peer && peer.onremovestream(event); - }; - } - return; - } - - dontDuplicate[event.stream.id] = event.stream.id; - - var streamsToShare = {}; - if (config.remoteSdp && config.remoteSdp.streamsToShare) { - streamsToShare = config.remoteSdp.streamsToShare; - } else if (config.streamsToShare) { - streamsToShare = config.streamsToShare; - } - - var streamToShare = streamsToShare[event.stream.id]; - if (streamToShare) { - event.stream.isAudio = streamToShare.isAudio; - event.stream.isVideo = streamToShare.isVideo; - event.stream.isScreen = streamToShare.isScreen; - } else { - event.stream.isVideo = !!getTracks(event.stream, 'video').length; - event.stream.isAudio = !event.stream.isVideo; - event.stream.isScreen = false; - } - - event.stream.streamid = event.stream.id; - - allRemoteStreams[event.stream.id] = event.stream; - config.onRemoteStream(event.stream); - - event.stream.getTracks().forEach(function(track) { - track.onended = function() { // track.onmute = - peer && peer.onremovestream(event); - }; - }); - - event.stream.onremovetrack = function() { - peer && peer.onremovestream(event); - }; - }; - - peer.onremovestream = function(event) { - // this event doesn't works anymore - event.stream.streamid = event.stream.id; - - if (allRemoteStreams[event.stream.id]) { - delete allRemoteStreams[event.stream.id]; - } - - config.onRemoteStreamRemoved(event.stream); - }; - - if (typeof peer.removeStream !== 'function') { - // removeStream backward compatibility - peer.removeStream = function(stream) { - stream.getTracks().forEach(function(track) { - peer.removeTrack(track, stream); - }); - }; - } - - this.addRemoteCandidate = function(remoteCandidate) { - peer.addIceCandidate(new RTCIceCandidate(remoteCandidate)); - }; - - function oldAddRemoteSdp(remoteSdp, cb) { - cb = cb || function() {}; - - if (DetectRTC.browser.name !== 'Safari') { - remoteSdp.sdp = connection.processSdp(remoteSdp.sdp); - } - peer.setRemoteDescription(new RTCSessionDescription(remoteSdp), cb, function(error) { - if (!!connection.enableLogs) { - console.error('setRemoteDescription failed', '\n', error, '\n', remoteSdp.sdp); - } - - cb(); - }); - } - - this.addRemoteSdp = function(remoteSdp, cb) { - cb = cb || function() {}; - - if (DetectRTC.browser.name !== 'Safari') { - remoteSdp.sdp = connection.processSdp(remoteSdp.sdp); - } - - peer.setRemoteDescription(new RTCSessionDescription(remoteSdp)).then(cb, function(error) { - if (!!connection.enableLogs) { - console.error('setRemoteDescription failed', '\n', error, '\n', remoteSdp.sdp); - } - - cb(); - }).catch(function(error) { - if (!!connection.enableLogs) { - console.error('setRemoteDescription failed', '\n', error, '\n', remoteSdp.sdp); - } - - cb(); - }); - }; - - var isOfferer = true; - - if (config.remoteSdp) { - isOfferer = false; - } - - this.createDataChannel = function() { - var channel = peer.createDataChannel('sctp', {}); - setChannelEvents(channel); - }; - - if (connection.session.data === true && !renegotiatingPeer) { - if (!isOfferer) { - peer.ondatachannel = function(event) { - var channel = event.channel; - setChannelEvents(channel); - }; - } else { - this.createDataChannel(); - } - } - - this.enableDisableVideoEncoding = function(enable) { - var rtcp; - peer.getSenders().forEach(function(sender) { - if (!rtcp && sender.track.kind === 'video') { - rtcp = sender; - } - }); - - if (!rtcp || !rtcp.getParameters) return; - - var parameters = rtcp.getParameters(); - parameters.encodings[1] && (parameters.encodings[1].active = !!enable); - parameters.encodings[2] && (parameters.encodings[2].active = !!enable); - rtcp.setParameters(parameters); - }; - - if (config.remoteSdp) { - if (config.remoteSdp.remotePeerSdpConstraints) { - sdpConstraints = config.remoteSdp.remotePeerSdpConstraints; - } - defaults.sdpConstraints = setSdpConstraints(sdpConstraints); - this.addRemoteSdp(config.remoteSdp, function() { - createOfferOrAnswer('createAnswer'); - }); - } - - function setChannelEvents(channel) { - // force ArrayBuffer in Firefox; which uses "Blob" by default. - channel.binaryType = 'arraybuffer'; - - channel.onmessage = function(event) { - config.onDataChannelMessage(event.data); - }; - - channel.onopen = function() { - config.onDataChannelOpened(channel); - }; - - channel.onerror = function(error) { - config.onDataChannelError(error); - }; - - channel.onclose = function(event) { - config.onDataChannelClosed(event); - }; - - channel.internalSend = channel.send; - channel.send = function(data) { - if (channel.readyState !== 'open') { - return; - } - - channel.internalSend(data); - }; - - peer.channel = channel; - } - - if (connection.session.audio == 'two-way' || connection.session.video == 'two-way' || connection.session.screen == 'two-way') { - defaults.sdpConstraints = setSdpConstraints({ - OfferToReceiveAudio: connection.session.audio == 'two-way' || (config.remoteSdp && config.remoteSdp.remotePeerSdpConstraints && config.remoteSdp.remotePeerSdpConstraints.OfferToReceiveAudio), - OfferToReceiveVideo: connection.session.video == 'two-way' || connection.session.screen == 'two-way' || (config.remoteSdp && config.remoteSdp.remotePeerSdpConstraints && config.remoteSdp.remotePeerSdpConstraints.OfferToReceiveAudio) - }); - } - - var streamsToShare = {}; - peer.getLocalStreams().forEach(function(stream) { - streamsToShare[stream.streamid] = { - isAudio: !!stream.isAudio, - isVideo: !!stream.isVideo, - isScreen: !!stream.isScreen - }; - }); - - function oldCreateOfferOrAnswer(_method) { - peer[_method](function(localSdp) { - if (DetectRTC.browser.name !== 'Safari') { - localSdp.sdp = connection.processSdp(localSdp.sdp); - } - peer.setLocalDescription(localSdp, function() { - if (!connection.trickleIce) return; - - config.onLocalSdp({ - type: localSdp.type, - sdp: localSdp.sdp, - remotePeerSdpConstraints: config.remotePeerSdpConstraints || false, - renegotiatingPeer: !!config.renegotiatingPeer || false, - connectionDescription: self.connectionDescription, - dontGetRemoteStream: !!config.dontGetRemoteStream, - extra: connection ? connection.extra : {}, - streamsToShare: streamsToShare - }); - - connection.onSettingLocalDescription(self); - }, function(error) { - if (!!connection.enableLogs) { - console.error('setLocalDescription-error', error); - } - }); - }, function(error) { - if (!!connection.enableLogs) { - console.error('sdp-' + _method + '-error', error); - } - }, defaults.sdpConstraints); - } - - function createOfferOrAnswer(_method) { - peer[_method](defaults.sdpConstraints).then(function(localSdp) { - if (DetectRTC.browser.name !== 'Safari') { - localSdp.sdp = connection.processSdp(localSdp.sdp); - } - peer.setLocalDescription(localSdp).then(function() { - if (!connection.trickleIce) return; - - config.onLocalSdp({ - type: localSdp.type, - sdp: localSdp.sdp, - remotePeerSdpConstraints: config.remotePeerSdpConstraints || false, - renegotiatingPeer: !!config.renegotiatingPeer || false, - connectionDescription: self.connectionDescription, - dontGetRemoteStream: !!config.dontGetRemoteStream, - extra: connection ? connection.extra : {}, - streamsToShare: streamsToShare - }); - - connection.onSettingLocalDescription(self); - }, function(error) { - if (!connection.enableLogs) return; - console.error('setLocalDescription error', error); - }); - }, function(error) { - if (!!connection.enableLogs) { - console.error('sdp-error', error); - } - }); - } - - if (isOfferer) { - createOfferOrAnswer('createOffer'); - } - - peer.nativeClose = peer.close; - peer.close = function() { - if (!peer) { - return; - } - - try { - if (peer.nativeClose !== peer.close) { - peer.nativeClose(); - } - } catch (e) {} - - peer = null; - self.peer = null; - }; - - this.peer = peer; - } - - // CodecsHandler.js - - var CodecsHandler = (function() { - // use "RTCRtpTransceiver.setCodecPreferences" - function preferCodec(sdp, codecName) { - var info = splitLines(sdp); - - if (!info.videoCodecNumbers) { - return sdp; - } - - if (codecName === 'vp8' && info.vp8LineNumber === info.videoCodecNumbers[0]) { - return sdp; - } - - if (codecName === 'vp9' && info.vp9LineNumber === info.videoCodecNumbers[0]) { - return sdp; - } - - if (codecName === 'h264' && info.h264LineNumber === info.videoCodecNumbers[0]) { - return sdp; - } - - sdp = preferCodecHelper(sdp, codecName, info); - - return sdp; - } - - function preferCodecHelper(sdp, codec, info, ignore) { - var preferCodecNumber = ''; - - if (codec === 'vp8') { - if (!info.vp8LineNumber) { - return sdp; - } - preferCodecNumber = info.vp8LineNumber; - } - - if (codec === 'vp9') { - if (!info.vp9LineNumber) { - return sdp; - } - preferCodecNumber = info.vp9LineNumber; - } - - if (codec === 'h264') { - if (!info.h264LineNumber) { - return sdp; - } - - preferCodecNumber = info.h264LineNumber; - } - - var newLine = info.videoCodecNumbersOriginal.split('SAVPF')[0] + 'SAVPF '; - - var newOrder = [preferCodecNumber]; - - if (ignore) { - newOrder = []; - } - - info.videoCodecNumbers.forEach(function(codecNumber) { - if (codecNumber === preferCodecNumber) return; - newOrder.push(codecNumber); - }); - - newLine += newOrder.join(' '); - - sdp = sdp.replace(info.videoCodecNumbersOriginal, newLine); - return sdp; - } - - function splitLines(sdp) { - var info = {}; - sdp.split('\n').forEach(function(line) { - if (line.indexOf('m=video') === 0) { - info.videoCodecNumbers = []; - line.split('SAVPF')[1].split(' ').forEach(function(codecNumber) { - codecNumber = codecNumber.trim(); - if (!codecNumber || !codecNumber.length) return; - info.videoCodecNumbers.push(codecNumber); - info.videoCodecNumbersOriginal = line; - }); - } - - if (line.indexOf('VP8/90000') !== -1 && !info.vp8LineNumber) { - info.vp8LineNumber = line.replace('a=rtpmap:', '').split(' ')[0]; - } - - if (line.indexOf('VP9/90000') !== -1 && !info.vp9LineNumber) { - info.vp9LineNumber = line.replace('a=rtpmap:', '').split(' ')[0]; - } - - if (line.indexOf('H264/90000') !== -1 && !info.h264LineNumber) { - info.h264LineNumber = line.replace('a=rtpmap:', '').split(' ')[0]; - } - }); - - return info; - } - - function removeVPX(sdp) { - var info = splitLines(sdp); - - // last parameter below means: ignore these codecs - sdp = preferCodecHelper(sdp, 'vp9', info, true); - sdp = preferCodecHelper(sdp, 'vp8', info, true); - - return sdp; - } - - function disableNACK(sdp) { - if (!sdp || typeof sdp !== 'string') { - throw 'Invalid arguments.'; - } - - sdp = sdp.replace('a=rtcp-fb:126 nack\r\n', ''); - sdp = sdp.replace('a=rtcp-fb:126 nack pli\r\n', 'a=rtcp-fb:126 pli\r\n'); - sdp = sdp.replace('a=rtcp-fb:97 nack\r\n', ''); - sdp = sdp.replace('a=rtcp-fb:97 nack pli\r\n', 'a=rtcp-fb:97 pli\r\n'); - - return sdp; - } - - function prioritize(codecMimeType, peer) { - if (!peer || !peer.getSenders || !peer.getSenders().length) { - return; - } - - if (!codecMimeType || typeof codecMimeType !== 'string') { - throw 'Invalid arguments.'; - } - - peer.getSenders().forEach(function(sender) { - var params = sender.getParameters(); - for (var i = 0; i < params.codecs.length; i++) { - if (params.codecs[i].mimeType == codecMimeType) { - params.codecs.unshift(params.codecs.splice(i, 1)); - break; - } - } - sender.setParameters(params); - }); - } - - function removeNonG722(sdp) { - return sdp.replace(/m=audio ([0-9]+) RTP\/SAVPF ([0-9 ]*)/g, 'm=audio $1 RTP\/SAVPF 9'); - } - - function setBAS(sdp, bandwidth, isScreen) { - if (!bandwidth) { - return sdp; - } - - if (typeof isFirefox !== 'undefined' && isFirefox) { - return sdp; - } - - if (isScreen) { - if (!bandwidth.screen) { - console.warn('It seems that you are not using bandwidth for screen. Screen sharing is expected to fail.'); - } else if (bandwidth.screen < 300) { - console.warn('It seems that you are using wrong bandwidth value for screen. Screen sharing is expected to fail.'); - } - } - - // if screen; must use at least 300kbs - if (bandwidth.screen && isScreen) { - sdp = sdp.replace(/b=AS([^\r\n]+\r\n)/g, ''); - sdp = sdp.replace(/a=mid:video\r\n/g, 'a=mid:video\r\nb=AS:' + bandwidth.screen + '\r\n'); - } - - // remove existing bandwidth lines - if (bandwidth.audio || bandwidth.video) { - sdp = sdp.replace(/b=AS([^\r\n]+\r\n)/g, ''); - } - - if (bandwidth.audio) { - sdp = sdp.replace(/a=mid:audio\r\n/g, 'a=mid:audio\r\nb=AS:' + bandwidth.audio + '\r\n'); - } - - if (bandwidth.screen) { - sdp = sdp.replace(/a=mid:video\r\n/g, 'a=mid:video\r\nb=AS:' + bandwidth.screen + '\r\n'); - } else if (bandwidth.video) { - sdp = sdp.replace(/a=mid:video\r\n/g, 'a=mid:video\r\nb=AS:' + bandwidth.video + '\r\n'); - } - - return sdp; - } - - // Find the line in sdpLines that starts with |prefix|, and, if specified, - // contains |substr| (case-insensitive search). - function findLine(sdpLines, prefix, substr) { - return findLineInRange(sdpLines, 0, -1, prefix, substr); - } - - // Find the line in sdpLines[startLine...endLine - 1] that starts with |prefix| - // and, if specified, contains |substr| (case-insensitive search). - function findLineInRange(sdpLines, startLine, endLine, prefix, substr) { - var realEndLine = endLine !== -1 ? endLine : sdpLines.length; - for (var i = startLine; i < realEndLine; ++i) { - if (sdpLines[i].indexOf(prefix) === 0) { - if (!substr || - sdpLines[i].toLowerCase().indexOf(substr.toLowerCase()) !== -1) { - return i; - } - } - } - return null; - } - - // Gets the codec payload type from an a=rtpmap:X line. - function getCodecPayloadType(sdpLine) { - var pattern = new RegExp('a=rtpmap:(\\d+) \\w+\\/\\d+'); - var result = sdpLine.match(pattern); - return (result && result.length === 2) ? result[1] : null; - } - - function setVideoBitrates(sdp, params) { - params = params || {}; - var xgoogle_min_bitrate = params.min; - var xgoogle_max_bitrate = params.max; - - var sdpLines = sdp.split('\r\n'); - - // VP8 - var vp8Index = findLine(sdpLines, 'a=rtpmap', 'VP8/90000'); - var vp8Payload; - if (vp8Index) { - vp8Payload = getCodecPayloadType(sdpLines[vp8Index]); - } - - if (!vp8Payload) { - return sdp; - } - - var rtxIndex = findLine(sdpLines, 'a=rtpmap', 'rtx/90000'); - var rtxPayload; - if (rtxIndex) { - rtxPayload = getCodecPayloadType(sdpLines[rtxIndex]); - } - - if (!rtxIndex) { - return sdp; - } - - var rtxFmtpLineIndex = findLine(sdpLines, 'a=fmtp:' + rtxPayload.toString()); - if (rtxFmtpLineIndex !== null) { - var appendrtxNext = '\r\n'; - appendrtxNext += 'a=fmtp:' + vp8Payload + ' x-google-min-bitrate=' + (xgoogle_min_bitrate || '228') + '; x-google-max-bitrate=' + (xgoogle_max_bitrate || '228'); - sdpLines[rtxFmtpLineIndex] = sdpLines[rtxFmtpLineIndex].concat(appendrtxNext); - sdp = sdpLines.join('\r\n'); - } - - return sdp; - } - - function setOpusAttributes(sdp, params) { - params = params || {}; - - var sdpLines = sdp.split('\r\n'); - - // Opus - var opusIndex = findLine(sdpLines, 'a=rtpmap', 'opus/48000'); - var opusPayload; - if (opusIndex) { - opusPayload = getCodecPayloadType(sdpLines[opusIndex]); - } - - if (!opusPayload) { - return sdp; - } - - var opusFmtpLineIndex = findLine(sdpLines, 'a=fmtp:' + opusPayload.toString()); - if (opusFmtpLineIndex === null) { - return sdp; - } - - var appendOpusNext = ''; - appendOpusNext += '; stereo=' + (typeof params.stereo != 'undefined' ? params.stereo : '1'); - appendOpusNext += '; sprop-stereo=' + (typeof params['sprop-stereo'] != 'undefined' ? params['sprop-stereo'] : '1'); - - if (typeof params.maxaveragebitrate != 'undefined') { - appendOpusNext += '; maxaveragebitrate=' + (params.maxaveragebitrate || 128 * 1024 * 8); - } - - if (typeof params.maxplaybackrate != 'undefined') { - appendOpusNext += '; maxplaybackrate=' + (params.maxplaybackrate || 128 * 1024 * 8); - } - - if (typeof params.cbr != 'undefined') { - appendOpusNext += '; cbr=' + (typeof params.cbr != 'undefined' ? params.cbr : '1'); - } - - if (typeof params.useinbandfec != 'undefined') { - appendOpusNext += '; useinbandfec=' + params.useinbandfec; - } - - if (typeof params.usedtx != 'undefined') { - appendOpusNext += '; usedtx=' + params.usedtx; - } - - if (typeof params.maxptime != 'undefined') { - appendOpusNext += '\r\na=maxptime:' + params.maxptime; - } - - sdpLines[opusFmtpLineIndex] = sdpLines[opusFmtpLineIndex].concat(appendOpusNext); - - sdp = sdpLines.join('\r\n'); - return sdp; - } - - // forceStereoAudio => via webrtcexample.com - // requires getUserMedia => echoCancellation:false - function forceStereoAudio(sdp) { - var sdpLines = sdp.split('\r\n'); - var fmtpLineIndex = null; - for (var i = 0; i < sdpLines.length; i++) { - if (sdpLines[i].search('opus/48000') !== -1) { - var opusPayload = extractSdp(sdpLines[i], /:(\d+) opus\/48000/i); - break; - } - } - for (var i = 0; i < sdpLines.length; i++) { - if (sdpLines[i].search('a=fmtp') !== -1) { - var payload = extractSdp(sdpLines[i], /a=fmtp:(\d+)/); - if (payload === opusPayload) { - fmtpLineIndex = i; - break; - } - } - } - if (fmtpLineIndex === null) return sdp; - sdpLines[fmtpLineIndex] = sdpLines[fmtpLineIndex].concat('; stereo=1; sprop-stereo=1'); - sdp = sdpLines.join('\r\n'); - return sdp; - } - - return { - removeVPX: removeVPX, - disableNACK: disableNACK, - prioritize: prioritize, - removeNonG722: removeNonG722, - setApplicationSpecificBandwidth: function(sdp, bandwidth, isScreen) { - return setBAS(sdp, bandwidth, isScreen); - }, - setVideoBitrates: function(sdp, params) { - return setVideoBitrates(sdp, params); - }, - setOpusAttributes: function(sdp, params) { - return setOpusAttributes(sdp, params); - }, - preferVP9: function(sdp) { - return preferCodec(sdp, 'vp9'); - }, - preferCodec: preferCodec, - forceStereoAudio: forceStereoAudio - }; - })(); - - // backward compatibility - window.BandwidthHandler = CodecsHandler; - - // OnIceCandidateHandler.js - - var OnIceCandidateHandler = (function() { - function processCandidates(connection, icePair) { - var candidate = icePair.candidate; - - var iceRestrictions = connection.candidates; - var stun = iceRestrictions.stun; - var turn = iceRestrictions.turn; - - if (!isNull(iceRestrictions.reflexive)) { - stun = iceRestrictions.reflexive; - } - - if (!isNull(iceRestrictions.relay)) { - turn = iceRestrictions.relay; - } - - if (!iceRestrictions.host && !!candidate.match(/typ host/g)) { - return; - } - - if (!turn && !!candidate.match(/typ relay/g)) { - return; - } - - if (!stun && !!candidate.match(/typ srflx/g)) { - return; - } - - var protocol = connection.iceProtocols; - - if (!protocol.udp && !!candidate.match(/ udp /g)) { - return; - } - - if (!protocol.tcp && !!candidate.match(/ tcp /g)) { - return; - } - - if (connection.enableLogs) { - console.debug('Your candidate pairs:', candidate); - } - - return { - candidate: candidate, - sdpMid: icePair.sdpMid, - sdpMLineIndex: icePair.sdpMLineIndex - }; - } - - return { - processCandidates: processCandidates - }; - })(); - - // IceServersHandler.js - - var IceServersHandler = (function() { - function getIceServers(connection) { - // resiprocate: 3344+4433 - // pions: 7575 - var iceServers = [{ - 'urls': [ - 'stun:stun.l.google.com:19302', - 'stun:stun1.l.google.com:19302', - 'stun:stun2.l.google.com:19302', - 'stun:stun.l.google.com:19302?transport=udp', - ] - }]; - - return iceServers; - } - - return { - getIceServers: getIceServers - }; - })(); - - // getUserMediaHandler.js - - function setStreamType(constraints, stream) { - if (constraints.mandatory && constraints.mandatory.chromeMediaSource) { - stream.isScreen = true; - } else if (constraints.mozMediaSource || constraints.mediaSource) { - stream.isScreen = true; - } else if (constraints.video) { - stream.isVideo = true; - } else if (constraints.audio) { - stream.isAudio = true; - } - } - - // allow users to manage this object (to support re-capturing of screen/etc.) - window.currentUserMediaRequest = { - streams: [], - mutex: false, - queueRequests: [], - remove: function(idInstance) { - this.mutex = false; - - var stream = this.streams[idInstance]; - if (!stream) { - return; - } - - stream = stream.stream; - - var options = stream.currentUserMediaRequestOptions; - - if (this.queueRequests.indexOf(options)) { - delete this.queueRequests[this.queueRequests.indexOf(options)]; - this.queueRequests = removeNullEntries(this.queueRequests); - } - - this.streams[idInstance].stream = null; - delete this.streams[idInstance]; - } - }; - - function getUserMediaHandler(options) { - if (currentUserMediaRequest.mutex === true) { - currentUserMediaRequest.queueRequests.push(options); - return; - } - currentUserMediaRequest.mutex = true; - - // easy way to match - var idInstance = JSON.stringify(options.localMediaConstraints); - - function streaming(stream, returnBack) { - setStreamType(options.localMediaConstraints, stream); - - var streamEndedEvent = 'ended'; - - if ('oninactive' in stream) { - streamEndedEvent = 'inactive'; - } - stream.addEventListener(streamEndedEvent, function() { - delete currentUserMediaRequest.streams[idInstance]; - - currentUserMediaRequest.mutex = false; - if (currentUserMediaRequest.queueRequests.indexOf(options)) { - delete currentUserMediaRequest.queueRequests[currentUserMediaRequest.queueRequests.indexOf(options)]; - currentUserMediaRequest.queueRequests = removeNullEntries(currentUserMediaRequest.queueRequests); - } - }, false); - - currentUserMediaRequest.streams[idInstance] = { - stream: stream - }; - currentUserMediaRequest.mutex = false; - - if (currentUserMediaRequest.queueRequests.length) { - getUserMediaHandler(currentUserMediaRequest.queueRequests.shift()); - } - - // callback - options.onGettingLocalMedia(stream, returnBack); - } - - if (currentUserMediaRequest.streams[idInstance]) { - streaming(currentUserMediaRequest.streams[idInstance].stream, true); - } else { - var isBlackBerry = !!(/BB10|BlackBerry/i.test(navigator.userAgent || '')); - if (isBlackBerry || typeof navigator.mediaDevices === 'undefined' || typeof navigator.mediaDevices.getUserMedia !== 'function') { - navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; - navigator.getUserMedia(options.localMediaConstraints, function(stream) { - stream.streamid = stream.streamid || stream.id || getRandomString(); - stream.idInstance = idInstance; - streaming(stream); - }, function(error) { - options.onLocalMediaError(error, options.localMediaConstraints); - }); - return; - } - - if (typeof navigator.mediaDevices === 'undefined') { - navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; - var getUserMediaSuccess = function() {}; - var getUserMediaFailure = function() {}; - - var getUserMediaStream, getUserMediaError; - navigator.mediaDevices = { - getUserMedia: function(hints) { - navigator.getUserMedia(hints, function(getUserMediaSuccess) { - getUserMediaSuccess(stream); - getUserMediaStream = stream; - }, function(error) { - getUserMediaFailure(error); - getUserMediaError = error; - }); - - return { - then: function(successCB) { - if (getUserMediaStream) { - successCB(getUserMediaStream); - return; - } - - getUserMediaSuccess = successCB; - - return { - then: function(failureCB) { - if (getUserMediaError) { - failureCB(getUserMediaError); - return; - } - - getUserMediaFailure = failureCB; - } - } - } - } - } - }; - } - - if (options.localMediaConstraints.isScreen === true) { - if (navigator.mediaDevices.getDisplayMedia) { - navigator.mediaDevices.getDisplayMedia(options.localMediaConstraints).then(function(stream) { - stream.streamid = stream.streamid || stream.id || getRandomString(); - stream.idInstance = idInstance; - - streaming(stream); - }).catch(function(error) { - options.onLocalMediaError(error, options.localMediaConstraints); - }); - } else if (navigator.getDisplayMedia) { - navigator.getDisplayMedia(options.localMediaConstraints).then(function(stream) { - stream.streamid = stream.streamid || stream.id || getRandomString(); - stream.idInstance = idInstance; - - streaming(stream); - }).catch(function(error) { - options.onLocalMediaError(error, options.localMediaConstraints); - }); - } else { - throw new Error('getDisplayMedia API is not availabe in this browser.'); - } - return; - } - - navigator.mediaDevices.getUserMedia(options.localMediaConstraints).then(function(stream) { - stream.streamid = stream.streamid || stream.id || getRandomString(); - stream.idInstance = idInstance; - - streaming(stream); - }).catch(function(error) { - options.onLocalMediaError(error, options.localMediaConstraints); - }); - } - } - - // StreamsHandler.js - - var StreamsHandler = (function() { - function handleType(type) { - if (!type) { - return; - } - - if (typeof type === 'string' || typeof type === 'undefined') { - return type; - } - - if (type.audio && type.video) { - return null; - } - - if (type.audio) { - return 'audio'; - } - - if (type.video) { - return 'video'; - } - - return; - } - - function setHandlers(stream, syncAction, connection) { - if (!stream || !stream.addEventListener) return; - - if (typeof syncAction == 'undefined' || syncAction == true) { - var streamEndedEvent = 'ended'; - - if ('oninactive' in stream) { - streamEndedEvent = 'inactive'; - } - - stream.addEventListener(streamEndedEvent, function() { - StreamsHandler.onSyncNeeded(this.streamid, streamEndedEvent); - }, false); - } - - stream.mute = function(type, isSyncAction) { - type = handleType(type); - - if (typeof isSyncAction !== 'undefined') { - syncAction = isSyncAction; - } - - if (typeof type == 'undefined' || type == 'audio') { - getTracks(stream, 'audio').forEach(function(track) { - track.enabled = false; - connection.streamEvents[stream.streamid].isAudioMuted = true; - }); - } - - if (typeof type == 'undefined' || type == 'video') { - getTracks(stream, 'video').forEach(function(track) { - track.enabled = false; - }); - } - - if (typeof syncAction == 'undefined' || syncAction == true) { - StreamsHandler.onSyncNeeded(stream.streamid, 'mute', type); - } - - connection.streamEvents[stream.streamid].muteType = type || 'both'; - - fireEvent(stream, 'mute', type); - }; - - stream.unmute = function(type, isSyncAction) { - type = handleType(type); - - if (typeof isSyncAction !== 'undefined') { - syncAction = isSyncAction; - } - - graduallyIncreaseVolume(); - - if (typeof type == 'undefined' || type == 'audio') { - getTracks(stream, 'audio').forEach(function(track) { - track.enabled = true; - connection.streamEvents[stream.streamid].isAudioMuted = false; - }); - } - - if (typeof type == 'undefined' || type == 'video') { - getTracks(stream, 'video').forEach(function(track) { - track.enabled = true; - }); - - // make sure that video unmute doesn't affects audio - if (typeof type !== 'undefined' && type == 'video' && connection.streamEvents[stream.streamid].isAudioMuted) { - (function looper(times) { - if (!times) { - times = 0; - } - - times++; - - // check until five-seconds - if (times < 100 && connection.streamEvents[stream.streamid].isAudioMuted) { - stream.mute('audio'); - - setTimeout(function() { - looper(times); - }, 50); - } - })(); - } - } - - if (typeof syncAction == 'undefined' || syncAction == true) { - StreamsHandler.onSyncNeeded(stream.streamid, 'unmute', type); - } - - connection.streamEvents[stream.streamid].unmuteType = type || 'both'; - - fireEvent(stream, 'unmute', type); - }; - - function graduallyIncreaseVolume() { - if (!connection.streamEvents[stream.streamid].mediaElement) { - return; - } - - var mediaElement = connection.streamEvents[stream.streamid].mediaElement; - mediaElement.volume = 0; - afterEach(200, 5, function() { - try { - mediaElement.volume += .20; - } catch (e) { - mediaElement.volume = 1; - } - }); - } - } - - function afterEach(setTimeoutInteval, numberOfTimes, callback, startedTimes) { - startedTimes = (startedTimes || 0) + 1; - if (startedTimes >= numberOfTimes) return; - - setTimeout(function() { - callback(); - afterEach(setTimeoutInteval, numberOfTimes, callback, startedTimes); - }, setTimeoutInteval); - } - - return { - setHandlers: setHandlers, - onSyncNeeded: function(streamid, action, type) {} - }; - })(); - - // TextReceiver.js & TextSender.js - - function TextReceiver(connection) { - var content = {}; - - function receive(data, userid, extra) { - // uuid is used to uniquely identify sending instance - var uuid = data.uuid; - if (!content[uuid]) { - content[uuid] = []; - } - - content[uuid].push(data.message); - - if (data.last) { - var message = content[uuid].join(''); - if (data.isobject) { - message = JSON.parse(message); - } - - // latency detection - var receivingTime = new Date().getTime(); - var latency = receivingTime - data.sendingTime; - - var e = { - data: message, - userid: userid, - extra: extra, - latency: latency - }; - - if (connection.autoTranslateText) { - e.original = e.data; - connection.Translator.TranslateText(e.data, function(translatedText) { - e.data = translatedText; - connection.onmessage(e); - }); - } else { - connection.onmessage(e); - } - - delete content[uuid]; - } - } - - return { - receive: receive - }; - } - - // TextSender.js - var TextSender = { - send: function(config) { - var connection = config.connection; - - var channel = config.channel, - remoteUserId = config.remoteUserId, - initialText = config.text, - packetSize = connection.chunkSize || 1000, - textToTransfer = '', - isobject = false; - - if (!isString(initialText)) { - isobject = true; - initialText = JSON.stringify(initialText); - } - - // uuid is used to uniquely identify sending instance - var uuid = getRandomString(); - var sendingTime = new Date().getTime(); - - sendText(initialText); - - function sendText(textMessage, text) { - var data = { - type: 'text', - uuid: uuid, - sendingTime: sendingTime - }; - - if (textMessage) { - text = textMessage; - data.packets = parseInt(text.length / packetSize); - } - - if (text.length > packetSize) { - data.message = text.slice(0, packetSize); - } else { - data.message = text; - data.last = true; - data.isobject = isobject; - } - - channel.send(data, remoteUserId); - - textToTransfer = text.slice(data.message.length); - - if (textToTransfer.length) { - setTimeout(function() { - sendText(null, textToTransfer); - }, connection.chunkInterval || 100); - } - } - } - }; - - // FileProgressBarHandler.js - - var FileProgressBarHandler = (function() { - function handle(connection) { - var progressHelper = {}; - - // www.RTCMultiConnection.org/docs/onFileStart/ - connection.onFileStart = function(file) { - var div = document.createElement('div'); - div.title = file.name; - div.innerHTML = ' '; - - if (file.remoteUserId) { - div.innerHTML += ' (Sharing with:' + file.remoteUserId + ')'; - } - - if (!connection.filesContainer) { - connection.filesContainer = document.body || document.documentElement; - } - - connection.filesContainer.insertBefore(div, connection.filesContainer.firstChild); - - if (!file.remoteUserId) { - progressHelper[file.uuid] = { - div: div, - progress: div.querySelector('progress'), - label: div.querySelector('label') - }; - progressHelper[file.uuid].progress.max = file.maxChunks; - return; - } - - if (!progressHelper[file.uuid]) { - progressHelper[file.uuid] = {}; - } - - progressHelper[file.uuid][file.remoteUserId] = { - div: div, - progress: div.querySelector('progress'), - label: div.querySelector('label') - }; - progressHelper[file.uuid][file.remoteUserId].progress.max = file.maxChunks; - }; - - // www.RTCMultiConnection.org/docs/onFileProgress/ - connection.onFileProgress = function(chunk) { - var helper = progressHelper[chunk.uuid]; - if (!helper) { - return; - } - if (chunk.remoteUserId) { - helper = progressHelper[chunk.uuid][chunk.remoteUserId]; - if (!helper) { - return; - } - } - - helper.progress.value = chunk.currentPosition || chunk.maxChunks || helper.progress.max; - updateLabel(helper.progress, helper.label); - }; - - // www.RTCMultiConnection.org/docs/onFileEnd/ - connection.onFileEnd = function(file) { - var helper = progressHelper[file.uuid]; - if (!helper) { - console.error('No such progress-helper element exist.', file); - return; - } - - if (file.remoteUserId) { - helper = progressHelper[file.uuid][file.remoteUserId]; - if (!helper) { - return; - } - } - - var div = helper.div; - if (file.type.indexOf('image') != -1) { - div.innerHTML = 'Download ' + file.name + '
'; - } else { - div.innerHTML = 'Download ' + file.name + '
'; - } - }; - - function updateLabel(progress, label) { - if (progress.position === -1) { - return; - } - - var position = +progress.position.toFixed(2).split('.')[1] || 100; - label.innerHTML = position + '%'; - } - } - - return { - handle: handle - }; - })(); - - // _____________________ - // RTCMultiConnection.js - - (function(connection) { - forceOptions = forceOptions || { - useDefaultDevices: true - }; - - connection.channel = connection.sessionid = (roomid || location.href.replace(/\/|:|#|\?|\$|\^|%|\.|`|~|!|\+|@|\[|\||]|\|*. /g, '').split('\n').join('').split('\r').join('')) + ''; - - var mPeer = new MultiPeers(connection); - - var preventDuplicateOnStreamEvents = {}; - mPeer.onGettingLocalMedia = function(stream, callback) { - callback = callback || function() {}; - - if (preventDuplicateOnStreamEvents[stream.streamid]) { - callback(); - return; - } - preventDuplicateOnStreamEvents[stream.streamid] = true; - - try { - stream.type = 'local'; - } catch (e) {} - - connection.setStreamEndHandler(stream); - - getRMCMediaElement(stream, function(mediaElement) { - mediaElement.id = stream.streamid; - mediaElement.muted = true; - mediaElement.volume = 0; - - if (connection.attachStreams.indexOf(stream) === -1) { - connection.attachStreams.push(stream); - } - - if (typeof StreamsHandler !== 'undefined') { - StreamsHandler.setHandlers(stream, true, connection); - } - var isAudioMuted = stream.getAudioTracks().filter(function(track) { - return track.enabled; - }).length === 0; - - connection.streamEvents[stream.streamid] = { - stream: stream, - type: 'local', - mediaElement: mediaElement, - userid: connection.userid, - extra: connection.extra, - streamid: stream.streamid, - isAudioMuted: isAudioMuted - }; - - try { - setHarkEvents(connection, connection.streamEvents[stream.streamid]); - setMuteHandlers(connection, connection.streamEvents[stream.streamid]); - - connection.onstream(connection.streamEvents[stream.streamid]); - } catch (e) { - // - } - - callback(); - }, connection); - }; - - mPeer.onGettingRemoteMedia = function(stream, remoteUserId) { - try { - stream.type = 'remote'; - } catch (e) {} - - connection.setStreamEndHandler(stream, 'remote-stream'); - - getRMCMediaElement(stream, function(mediaElement) { - mediaElement.id = stream.streamid; - - if (typeof StreamsHandler !== 'undefined') { - StreamsHandler.setHandlers(stream, false, connection); - } - - connection.streamEvents[stream.streamid] = { - stream: stream, - type: 'remote', - userid: remoteUserId, - extra: connection.peers[remoteUserId] ? connection.peers[remoteUserId].extra : {}, - mediaElement: mediaElement, - streamid: stream.streamid - }; - - setMuteHandlers(connection, connection.streamEvents[stream.streamid]); - - connection.onstream(connection.streamEvents[stream.streamid]); - }, connection); - }; - - mPeer.onRemovingRemoteMedia = function(stream, remoteUserId) { - var streamEvent = connection.streamEvents[stream.streamid]; - if (!streamEvent) { - streamEvent = { - stream: stream, - type: 'remote', - userid: remoteUserId, - extra: connection.peers[remoteUserId] ? connection.peers[remoteUserId].extra : {}, - streamid: stream.streamid, - mediaElement: connection.streamEvents[stream.streamid] ? connection.streamEvents[stream.streamid].mediaElement : null - }; - } - - if (connection.peersBackup[streamEvent.userid]) { - streamEvent.extra = connection.peersBackup[streamEvent.userid].extra; - } - - connection.onstreamended(streamEvent); - - delete connection.streamEvents[stream.streamid]; - }; - - mPeer.onNegotiationNeeded = function(message, remoteUserId, callback) { - callback = callback || function() {}; - - remoteUserId = remoteUserId || message.remoteUserId; - message = message || ''; - - // usually a message looks like this - var messageToDeliver = { - remoteUserId: remoteUserId, - message: message, - sender: connection.userid - }; - - if (message.remoteUserId && message.message && message.sender) { - // if a code is manually passing required data - messageToDeliver = message; - } - - connectSocket(function() { - connection.socket.emit(connection.socketMessageEvent, messageToDeliver, callback); - }); - }; - - function onUserLeft(remoteUserId) { - connection.deletePeer(remoteUserId); - } - - mPeer.onUserLeft = onUserLeft; - mPeer.disconnectWith = function(remoteUserId, callback) { - if (connection.socket) { - connection.socket.emit('disconnect-with', remoteUserId, callback || function() {}); - } - - connection.deletePeer(remoteUserId); - }; - - connection.socketOptions = { - // 'force new connection': true, // For SocketIO version < 1.0 - // 'forceNew': true, // For SocketIO version >= 1.0 - 'transport': 'polling' // fixing transport:unknown issues - }; - - function connectSocket(connectCallback) { - connection.socketAutoReConnect = true; - - if (connection.socket) { // todo: check here readySate/etc. to make sure socket is still opened - if (connectCallback) { - connectCallback(connection.socket); - } - return; - } - - if (typeof SocketConnection === 'undefined') { - if (typeof FirebaseConnection !== 'undefined') { - window.SocketConnection = FirebaseConnection; - } else if (typeof PubNubConnection !== 'undefined') { - window.SocketConnection = PubNubConnection; - } else { - throw 'SocketConnection.js seems missed.'; - } - } - - new SocketConnection(connection, function(s) { - if (connectCallback) { - connectCallback(connection.socket); - } - }); - } - - // 1st paramter is roomid - // 2rd paramter is a callback function - connection.openOrJoin = function(roomid, callback) { - callback = callback || function() {}; - - connection.checkPresence(roomid, function(isRoomExist, roomid) { - if (isRoomExist) { - connection.sessionid = roomid; - - var localPeerSdpConstraints = false; - var remotePeerSdpConstraints = false; - var isOneWay = !!connection.session.oneway; - var isDataOnly = isData(connection.session); - - remotePeerSdpConstraints = { - OfferToReceiveAudio: connection.sdpConstraints.mandatory.OfferToReceiveAudio, - OfferToReceiveVideo: connection.sdpConstraints.mandatory.OfferToReceiveVideo - } - - localPeerSdpConstraints = { - OfferToReceiveAudio: isOneWay ? !!connection.session.audio : connection.sdpConstraints.mandatory.OfferToReceiveAudio, - OfferToReceiveVideo: isOneWay ? !!connection.session.video || !!connection.session.screen : connection.sdpConstraints.mandatory.OfferToReceiveVideo - } - - var connectionDescription = { - remoteUserId: connection.sessionid, - message: { - newParticipationRequest: true, - isOneWay: isOneWay, - isDataOnly: isDataOnly, - localPeerSdpConstraints: localPeerSdpConstraints, - remotePeerSdpConstraints: remotePeerSdpConstraints - }, - sender: connection.userid - }; - - beforeJoin(connectionDescription.message, function() { - joinRoom(connectionDescription, callback); - }); - return; - } - - connection.waitingForLocalMedia = true; - connection.isInitiator = true; - - connection.sessionid = roomid || connection.sessionid; - - if (isData(connection.session)) { - openRoom(callback); - return; - } - - connection.captureUserMedia(function() { - openRoom(callback); - }); - }); - }; - - // don't allow someone to join this person until he has the media - connection.waitingForLocalMedia = false; - - connection.open = function(roomid, callback) { - callback = callback || function() {}; - - connection.waitingForLocalMedia = true; - connection.isInitiator = true; - - connection.sessionid = roomid || connection.sessionid; - - connectSocket(function() { - if (isData(connection.session)) { - openRoom(callback); - return; - } - - connection.captureUserMedia(function() { - openRoom(callback); - }); - }); - }; - - // this object keeps extra-data records for all connected users - // this object is never cleared so you can always access extra-data even if a user left - connection.peersBackup = {}; - - connection.deletePeer = function(remoteUserId) { - if (!remoteUserId || !connection.peers[remoteUserId]) { - return; - } - - var eventObject = { - userid: remoteUserId, - extra: connection.peers[remoteUserId] ? connection.peers[remoteUserId].extra : {} - }; - - if (connection.peersBackup[eventObject.userid]) { - eventObject.extra = connection.peersBackup[eventObject.userid].extra; - } - - connection.onleave(eventObject); - - if (!!connection.peers[remoteUserId]) { - connection.peers[remoteUserId].streams.forEach(function(stream) { - stream.stop(); - }); - - var peer = connection.peers[remoteUserId].peer; - if (peer && peer.iceConnectionState !== 'closed') { - try { - peer.close(); - } catch (e) {} - } - - if (connection.peers[remoteUserId]) { - connection.peers[remoteUserId].peer = null; - delete connection.peers[remoteUserId]; - } - } - } - - connection.rejoin = function(connectionDescription) { - if (connection.isInitiator || !connectionDescription || !Object.keys(connectionDescription).length) { - return; - } - - var extra = {}; - - if (connection.peers[connectionDescription.remoteUserId]) { - extra = connection.peers[connectionDescription.remoteUserId].extra; - connection.deletePeer(connectionDescription.remoteUserId); - } - - if (connectionDescription && connectionDescription.remoteUserId) { - connection.join(connectionDescription.remoteUserId); - - connection.onReConnecting({ - userid: connectionDescription.remoteUserId, - extra: extra - }); - } - }; - - connection.join = function(remoteUserId, options) { - connection.sessionid = (remoteUserId ? remoteUserId.sessionid || remoteUserId.remoteUserId || remoteUserId : false) || connection.sessionid; - connection.sessionid += ''; - - var localPeerSdpConstraints = false; - var remotePeerSdpConstraints = false; - var isOneWay = false; - var isDataOnly = false; - - if ((remoteUserId && remoteUserId.session) || !remoteUserId || typeof remoteUserId === 'string') { - var session = remoteUserId ? remoteUserId.session || connection.session : connection.session; - - isOneWay = !!session.oneway; - isDataOnly = isData(session); - - remotePeerSdpConstraints = { - OfferToReceiveAudio: connection.sdpConstraints.mandatory.OfferToReceiveAudio, - OfferToReceiveVideo: connection.sdpConstraints.mandatory.OfferToReceiveVideo - }; - - localPeerSdpConstraints = { - OfferToReceiveAudio: isOneWay ? !!connection.session.audio : connection.sdpConstraints.mandatory.OfferToReceiveAudio, - OfferToReceiveVideo: isOneWay ? !!connection.session.video || !!connection.session.screen : connection.sdpConstraints.mandatory.OfferToReceiveVideo - }; - } - - options = options || {}; - - var cb = function() {}; - if (typeof options === 'function') { - cb = options; - options = {}; - } - - if (typeof options.localPeerSdpConstraints !== 'undefined') { - localPeerSdpConstraints = options.localPeerSdpConstraints; - } - - if (typeof options.remotePeerSdpConstraints !== 'undefined') { - remotePeerSdpConstraints = options.remotePeerSdpConstraints; - } - - if (typeof options.isOneWay !== 'undefined') { - isOneWay = options.isOneWay; - } - - if (typeof options.isDataOnly !== 'undefined') { - isDataOnly = options.isDataOnly; - } - - var connectionDescription = { - remoteUserId: connection.sessionid, - message: { - newParticipationRequest: true, - isOneWay: isOneWay, - isDataOnly: isDataOnly, - localPeerSdpConstraints: localPeerSdpConstraints, - remotePeerSdpConstraints: remotePeerSdpConstraints - }, - sender: connection.userid - }; - - beforeJoin(connectionDescription.message, function() { - connectSocket(function() { - joinRoom(connectionDescription, cb); - }); - }); - return connectionDescription; - }; - - function joinRoom(connectionDescription, cb) { - connection.socket.emit('join-room', { - sessionid: connection.sessionid, - session: connection.session, - mediaConstraints: connection.mediaConstraints, - sdpConstraints: connection.sdpConstraints, - streams: getStreamInfoForAdmin(), - extra: connection.extra, - password: typeof connection.password !== 'undefined' && typeof connection.password !== 'object' ? connection.password : '' - }, function(isRoomJoined, error) { - if (isRoomJoined === true) { - if (connection.enableLogs) { - console.log('isRoomJoined: ', isRoomJoined, ' roomid: ', connection.sessionid); - } - - if (!!connection.peers[connection.sessionid]) { - // on socket disconnect & reconnect - return; - } - - mPeer.onNegotiationNeeded(connectionDescription); - } - - if (isRoomJoined === false) { - if (connection.enableLogs) { - console.warn('isRoomJoined: ', error, ' roomid: ', connection.sessionid); - } - - // [disabled] retry after 3 seconds - false && setTimeout(function() { - joinRoom(connectionDescription, cb); - }, 3000); - } - - cb(isRoomJoined, connection.sessionid, error); - }); - } - - connection.publicRoomIdentifier = ''; - - function openRoom(callback) { - if (connection.enableLogs) { - console.log('Sending open-room signal to socket.io'); - } - - connection.waitingForLocalMedia = false; - connection.socket.emit('open-room', { - sessionid: connection.sessionid, - session: connection.session, - mediaConstraints: connection.mediaConstraints, - sdpConstraints: connection.sdpConstraints, - streams: getStreamInfoForAdmin(), - extra: connection.extra, - identifier: connection.publicRoomIdentifier, - password: typeof connection.password !== 'undefined' && typeof connection.password !== 'object' ? connection.password : '' - }, function(isRoomOpened, error) { - if (isRoomOpened === true) { - if (connection.enableLogs) { - console.log('isRoomOpened: ', isRoomOpened, ' roomid: ', connection.sessionid); - } - callback(isRoomOpened, connection.sessionid); - } - - if (isRoomOpened === false) { - if (connection.enableLogs) { - console.warn('isRoomOpened: ', error, ' roomid: ', connection.sessionid); - } - - callback(isRoomOpened, connection.sessionid, error); - } - }); - } - - function getStreamInfoForAdmin() { - try { - return connection.streamEvents.selectAll('local').map(function(event) { - return { - streamid: event.streamid, - tracks: event.stream.getTracks().length - }; - }); - } catch (e) { - return []; - } - } - - function beforeJoin(userPreferences, callback) { - if (connection.dontCaptureUserMedia || userPreferences.isDataOnly) { - callback(); - return; - } - - var localMediaConstraints = {}; - - if (userPreferences.localPeerSdpConstraints.OfferToReceiveAudio) { - localMediaConstraints.audio = connection.mediaConstraints.audio; - } - - if (userPreferences.localPeerSdpConstraints.OfferToReceiveVideo) { - localMediaConstraints.video = connection.mediaConstraints.video; - } - - var session = userPreferences.session || connection.session; - - if (session.oneway && session.audio !== 'two-way' && session.video !== 'two-way' && session.screen !== 'two-way') { - callback(); - return; - } - - if (session.oneway && session.audio && session.audio === 'two-way') { - session = { - audio: true - }; - } - - if (session.audio || session.video || session.screen) { - if (session.screen) { - if (DetectRTC.browser.name === 'Edge') { - navigator.getDisplayMedia({ - video: true, - audio: isAudioPlusTab(connection) - }).then(function(screen) { - screen.isScreen = true; - mPeer.onGettingLocalMedia(screen); - - if ((session.audio || session.video) && !isAudioPlusTab(connection)) { - connection.invokeGetUserMedia(null, callback); - } else { - callback(screen); - } - }, function(error) { - console.error('Unable to capture screen on Edge. HTTPs and version 17+ is required.'); - }); - } else { - connection.invokeGetUserMedia({ - audio: isAudioPlusTab(connection), - video: true, - isScreen: true - }, (session.audio || session.video) && !isAudioPlusTab(connection) ? connection.invokeGetUserMedia(null, callback) : callback); - } - } else if (session.audio || session.video) { - connection.invokeGetUserMedia(null, callback, session); - } - } - } - - connection.getUserMedia = connection.captureUserMedia = function(callback, sessionForced) { - callback = callback || function() {}; - var session = sessionForced || connection.session; - - if (connection.dontCaptureUserMedia || isData(session)) { - callback(); - return; - } - - if (session.audio || session.video || session.screen) { - if (session.screen) { - if (DetectRTC.browser.name === 'Edge') { - navigator.getDisplayMedia({ - video: true, - audio: isAudioPlusTab(connection) - }).then(function(screen) { - screen.isScreen = true; - mPeer.onGettingLocalMedia(screen); - - if ((session.audio || session.video) && !isAudioPlusTab(connection)) { - var nonScreenSession = {}; - for (var s in session) { - if (s !== 'screen') { - nonScreenSession[s] = session[s]; - } - } - connection.invokeGetUserMedia(sessionForced, callback, nonScreenSession); - return; - } - callback(screen); - }, function(error) { - console.error('Unable to capture screen on Edge. HTTPs and version 17+ is required.'); - }); - } else { - connection.invokeGetUserMedia({ - audio: isAudioPlusTab(connection), - video: true, - isScreen: true - }, function(stream) { - if ((session.audio || session.video) && !isAudioPlusTab(connection)) { - var nonScreenSession = {}; - for (var s in session) { - if (s !== 'screen') { - nonScreenSession[s] = session[s]; - } - } - connection.invokeGetUserMedia(sessionForced, callback, nonScreenSession); - return; - } - callback(stream); - }); - } - } else if (session.audio || session.video) { - connection.invokeGetUserMedia(sessionForced, callback, session); - } - } - }; - - connection.onbeforeunload = function(arg1, dontCloseSocket) { - if (!connection.closeBeforeUnload) { - return; - } - - connection.peers.getAllParticipants().forEach(function(participant) { - mPeer.onNegotiationNeeded({ - userLeft: true - }, participant); - - if (connection.peers[participant] && connection.peers[participant].peer) { - connection.peers[participant].peer.close(); - } - - delete connection.peers[participant]; - }); - - if (!dontCloseSocket) { - connection.closeSocket(); - } - - connection.isInitiator = false; - }; - - if (!window.ignoreBeforeUnload) { - // user can implement its own version of window.onbeforeunload - connection.closeBeforeUnload = true; - window.addEventListener('beforeunload', connection.onbeforeunload, false); - } else { - connection.closeBeforeUnload = false; - } - - connection.userid = getRandomString(); - connection.changeUserId = function(newUserId, callback) { - callback = callback || function() {}; - connection.userid = newUserId || getRandomString(); - connection.socket.emit('changed-uuid', connection.userid, callback); - }; - - connection.extra = {}; - connection.attachStreams = []; - - connection.session = { - audio: true, - video: true - }; - - connection.enableFileSharing = false; - - // all values in kbps - connection.bandwidth = { - screen: false, - audio: false, - video: false - }; - - connection.codecs = { - audio: 'opus', - video: 'VP9' - }; - - connection.processSdp = function(sdp) { - // ignore SDP modification if unified-pan is supported - if (isUnifiedPlanSupportedDefault()) { - return sdp; - } - - if (DetectRTC.browser.name === 'Safari') { - return sdp; - } - - if (connection.codecs.video.toUpperCase() === 'VP8') { - sdp = CodecsHandler.preferCodec(sdp, 'vp8'); - } - - if (connection.codecs.video.toUpperCase() === 'VP9') { - sdp = CodecsHandler.preferCodec(sdp, 'vp9'); - } - - if (connection.codecs.video.toUpperCase() === 'H264') { - sdp = CodecsHandler.preferCodec(sdp, 'h264'); - } - - if (connection.codecs.audio === 'G722') { - sdp = CodecsHandler.removeNonG722(sdp); - } - - if (DetectRTC.browser.name === 'Firefox') { - return sdp; - } - - if (connection.bandwidth.video || connection.bandwidth.screen) { - sdp = CodecsHandler.setApplicationSpecificBandwidth(sdp, connection.bandwidth, !!connection.session.screen); - } - - if (connection.bandwidth.video) { - sdp = CodecsHandler.setVideoBitrates(sdp, { - min: connection.bandwidth.video * 8 * 1024, - max: connection.bandwidth.video * 8 * 1024 - }); - } - - if (connection.bandwidth.audio) { - sdp = CodecsHandler.setOpusAttributes(sdp, { - maxaveragebitrate: connection.bandwidth.audio * 8 * 1024, - maxplaybackrate: connection.bandwidth.audio * 8 * 1024, - stereo: 1, - maxptime: 3 - }); - } - - return sdp; - }; - - if (typeof CodecsHandler !== 'undefined') { - connection.BandwidthHandler = connection.CodecsHandler = CodecsHandler; - } - - connection.mediaConstraints = { - audio: { - mandatory: {}, - optional: connection.bandwidth.audio ? [{ - bandwidth: connection.bandwidth.audio * 8 * 1024 || 128 * 8 * 1024 - }] : [] - }, - video: { - mandatory: {}, - optional: connection.bandwidth.video ? [{ - bandwidth: connection.bandwidth.video * 8 * 1024 || 128 * 8 * 1024 - }, { - facingMode: 'user' - }] : [{ - facingMode: 'user' - }] - } - }; - - if (DetectRTC.browser.name === 'Firefox') { - connection.mediaConstraints = { - audio: true, - video: true - }; - } - - if (!forceOptions.useDefaultDevices && !DetectRTC.isMobileDevice) { - DetectRTC.load(function() { - var lastAudioDevice, lastVideoDevice; - // it will force RTCMultiConnection to capture last-devices - // i.e. if external microphone is attached to system, we should prefer it over built-in devices. - DetectRTC.MediaDevices.forEach(function(device) { - if (device.kind === 'audioinput' && connection.mediaConstraints.audio !== false) { - lastAudioDevice = device; - } - - if (device.kind === 'videoinput' && connection.mediaConstraints.video !== false) { - lastVideoDevice = device; - } - }); - - if (lastAudioDevice) { - if (DetectRTC.browser.name === 'Firefox') { - if (connection.mediaConstraints.audio !== true) { - connection.mediaConstraints.audio.deviceId = lastAudioDevice.id; - } else { - connection.mediaConstraints.audio = { - deviceId: lastAudioDevice.id - } - } - return; - } - - if (connection.mediaConstraints.audio == true) { - connection.mediaConstraints.audio = { - mandatory: {}, - optional: [] - } - } - - if (!connection.mediaConstraints.audio.optional) { - connection.mediaConstraints.audio.optional = []; - } - - var optional = [{ - sourceId: lastAudioDevice.id - }]; - - connection.mediaConstraints.audio.optional = optional.concat(connection.mediaConstraints.audio.optional); - } - - if (lastVideoDevice) { - if (DetectRTC.browser.name === 'Firefox') { - if (connection.mediaConstraints.video !== true) { - connection.mediaConstraints.video.deviceId = lastVideoDevice.id; - } else { - connection.mediaConstraints.video = { - deviceId: lastVideoDevice.id - } - } - return; - } - - if (connection.mediaConstraints.video == true) { - connection.mediaConstraints.video = { - mandatory: {}, - optional: [] - } - } - - if (!connection.mediaConstraints.video.optional) { - connection.mediaConstraints.video.optional = []; - } - - var optional = [{ - sourceId: lastVideoDevice.id - }]; - - connection.mediaConstraints.video.optional = optional.concat(connection.mediaConstraints.video.optional); - } - }); - } - - connection.sdpConstraints = { - mandatory: { - OfferToReceiveAudio: true, - OfferToReceiveVideo: true - }, - optional: [{ - VoiceActivityDetection: false - }] - }; - - connection.sdpSemantics = null; // "unified-plan" or "plan-b", ref: webrtc.org/web-apis/chrome/unified-plan/ - connection.iceCandidatePoolSize = null; // 0 - connection.bundlePolicy = null; // max-bundle - connection.rtcpMuxPolicy = null; // "require" or "negotiate" - connection.iceTransportPolicy = null; // "relay" or "all" - connection.optionalArgument = { - optional: [{ - DtlsSrtpKeyAgreement: true - }, { - googImprovedWifiBwe: true - }, { - googScreencastMinBitrate: 300 - }, { - googIPv6: true - }, { - googDscp: true - }, { - googCpuUnderuseThreshold: 55 - }, { - googCpuOveruseThreshold: 85 - }, { - googSuspendBelowMinBitrate: true - }, { - googCpuOveruseDetection: true - }], - mandatory: {} - }; - - connection.iceServers = IceServersHandler.getIceServers(connection); - - connection.candidates = { - host: true, - stun: true, - turn: true - }; - - connection.iceProtocols = { - tcp: true, - udp: true - }; - - // EVENTs - connection.onopen = function(event) { - if (!!connection.enableLogs) { - console.info('Data connection has been opened between you & ', event.userid); - } - }; - - connection.onclose = function(event) { - if (!!connection.enableLogs) { - console.warn('Data connection has been closed between you & ', event.userid); - } - }; - - connection.onerror = function(error) { - if (!!connection.enableLogs) { - console.error(error.userid, 'data-error', error); - } - }; - - connection.onmessage = function(event) { - if (!!connection.enableLogs) { - console.debug('data-message', event.userid, event.data); - } - }; - - connection.send = function(data, remoteUserId) { - connection.peers.send(data, remoteUserId); - }; - - connection.close = connection.disconnect = connection.leave = function() { - connection.onbeforeunload(false, true); - }; - - connection.closeEntireSession = function(callback) { - callback = callback || function() {}; - connection.socket.emit('close-entire-session', function looper() { - if (connection.getAllParticipants().length) { - setTimeout(looper, 100); - return; - } - - connection.onEntireSessionClosed({ - sessionid: connection.sessionid, - userid: connection.userid, - extra: connection.extra - }); - - connection.changeUserId(null, function() { - connection.close(); - callback(); - }); - }); - }; - - connection.onEntireSessionClosed = function(event) { - if (!connection.enableLogs) return; - console.info('Entire session is closed: ', event.sessionid, event.extra); - }; - - connection.onstream = function(e) { - var parentNode = connection.videosContainer; - parentNode.insertBefore(e.mediaElement, parentNode.firstChild); - var played = e.mediaElement.play(); - - if (typeof played !== 'undefined') { - played.catch(function() { - /*** iOS 11 doesn't allow automatic play and rejects ***/ - }).then(function() { - setTimeout(function() { - e.mediaElement.play(); - }, 2000); - }); - return; - } - - setTimeout(function() { - e.mediaElement.play(); - }, 2000); - }; - - connection.onstreamended = function(e) { - if (!e.mediaElement) { - e.mediaElement = document.getElementById(e.streamid); - } - - if (!e.mediaElement || !e.mediaElement.parentNode) { - return; - } - - e.mediaElement.parentNode.removeChild(e.mediaElement); - }; - - connection.direction = 'many-to-many'; - - connection.removeStream = function(streamid, remoteUserId) { - var stream; - connection.attachStreams.forEach(function(localStream) { - if (localStream.id === streamid) { - stream = localStream; - } - }); - - if (!stream) { - console.warn('No such stream exist.', streamid); - return; - } - - connection.peers.getAllParticipants().forEach(function(participant) { - if (remoteUserId && participant !== remoteUserId) { - return; - } - - var user = connection.peers[participant]; - try { - user.peer.removeStream(stream); - } catch (e) {} - }); - - connection.renegotiate(); - }; - - connection.addStream = function(session, remoteUserId) { - if (!!session.getTracks) { - if (connection.attachStreams.indexOf(session) === -1) { - if (!session.streamid) { - session.streamid = session.id; - } - - connection.attachStreams.push(session); - } - connection.renegotiate(remoteUserId); - return; - } - - if (isData(session)) { - connection.renegotiate(remoteUserId); - return; - } - - if (session.audio || session.video || session.screen) { - if (session.screen) { - if (DetectRTC.browser.name === 'Edge') { - navigator.getDisplayMedia({ - video: true, - audio: isAudioPlusTab(connection) - }).then(function(screen) { - screen.isScreen = true; - mPeer.onGettingLocalMedia(screen); - - if ((session.audio || session.video) && !isAudioPlusTab(connection)) { - connection.invokeGetUserMedia(null, function(stream) { - gumCallback(stream); - }); - } else { - gumCallback(screen); - } - }, function(error) { - console.error('Unable to capture screen on Edge. HTTPs and version 17+ is required.'); - }); - } else { - connection.invokeGetUserMedia({ - audio: isAudioPlusTab(connection), - video: true, - isScreen: true - }, function(stream) { - if ((session.audio || session.video) && !isAudioPlusTab(connection)) { - connection.invokeGetUserMedia(null, function(stream) { - gumCallback(stream); - }); - } else { - gumCallback(stream); - } - }); - } - } else if (session.audio || session.video) { - connection.invokeGetUserMedia(null, gumCallback); - } - } - - function gumCallback(stream) { - if (session.streamCallback) { - session.streamCallback(stream); - } - - connection.renegotiate(remoteUserId); - } - }; - - connection.invokeGetUserMedia = function(localMediaConstraints, callback, session) { - if (!session) { - session = connection.session; - } - - if (!localMediaConstraints) { - localMediaConstraints = connection.mediaConstraints; - } - - getUserMediaHandler({ - onGettingLocalMedia: function(stream) { - var videoConstraints = localMediaConstraints.video; - if (videoConstraints) { - if (videoConstraints.mediaSource || videoConstraints.mozMediaSource) { - stream.isScreen = true; - } else if (videoConstraints.mandatory && videoConstraints.mandatory.chromeMediaSource) { - stream.isScreen = true; - } - } - - if (!stream.isScreen) { - stream.isVideo = !!getTracks(stream, 'video').length; - stream.isAudio = !stream.isVideo && getTracks(stream, 'audio').length; - } - - mPeer.onGettingLocalMedia(stream, function() { - if (typeof callback === 'function') { - callback(stream); - } - }); - }, - onLocalMediaError: function(error, constraints) { - mPeer.onLocalMediaError(error, constraints); - }, - localMediaConstraints: localMediaConstraints || { - audio: session.audio ? localMediaConstraints.audio : false, - video: session.video ? localMediaConstraints.video : false - } - }); - }; - - function applyConstraints(stream, mediaConstraints) { - if (!stream) { - if (!!connection.enableLogs) { - console.error('No stream to applyConstraints.'); - } - return; - } - - if (mediaConstraints.audio) { - getTracks(stream, 'audio').forEach(function(track) { - track.applyConstraints(mediaConstraints.audio); - }); - } - - if (mediaConstraints.video) { - getTracks(stream, 'video').forEach(function(track) { - track.applyConstraints(mediaConstraints.video); - }); - } - } - - connection.applyConstraints = function(mediaConstraints, streamid) { - if (!MediaStreamTrack || !MediaStreamTrack.prototype.applyConstraints) { - alert('track.applyConstraints is NOT supported in your browser.'); - return; - } - - if (streamid) { - var stream; - if (connection.streamEvents[streamid]) { - stream = connection.streamEvents[streamid].stream; - } - applyConstraints(stream, mediaConstraints); - return; - } - - connection.attachStreams.forEach(function(stream) { - applyConstraints(stream, mediaConstraints); - }); - }; - - function replaceTrack(track, remoteUserId, isVideoTrack) { - if (remoteUserId) { - mPeer.replaceTrack(track, remoteUserId, isVideoTrack); - return; - } - - connection.peers.getAllParticipants().forEach(function(participant) { - mPeer.replaceTrack(track, participant, isVideoTrack); - }); - } - - connection.replaceTrack = function(session, remoteUserId, isVideoTrack) { - session = session || {}; - - if (!RTCPeerConnection.prototype.getSenders) { - connection.addStream(session); - return; - } - - if (session instanceof MediaStreamTrack) { - replaceTrack(session, remoteUserId, isVideoTrack); - return; - } - - if (session instanceof MediaStream) { - if (getTracks(session, 'video').length) { - replaceTrack(getTracks(session, 'video')[0], remoteUserId, true); - } - - if (getTracks(session, 'audio').length) { - replaceTrack(getTracks(session, 'audio')[0], remoteUserId, false); - } - return; - } - - if (isData(session)) { - throw 'connection.replaceTrack requires audio and/or video and/or screen.'; - return; - } - - if (session.audio || session.video || session.screen) { - if (session.screen) { - if (DetectRTC.browser.name === 'Edge') { - navigator.getDisplayMedia({ - video: true, - audio: isAudioPlusTab(connection) - }).then(function(screen) { - screen.isScreen = true; - mPeer.onGettingLocalMedia(screen); - - if ((session.audio || session.video) && !isAudioPlusTab(connection)) { - connection.invokeGetUserMedia(null, gumCallback); - } else { - gumCallback(screen); - } - }, function(error) { - console.error('Unable to capture screen on Edge. HTTPs and version 17+ is required.'); - }); - } else { - connection.invokeGetUserMedia({ - audio: isAudioPlusTab(connection), - video: true, - isScreen: true - }, (session.audio || session.video) && !isAudioPlusTab(connection) ? connection.invokeGetUserMedia(null, gumCallback) : gumCallback); - } - } else if (session.audio || session.video) { - connection.invokeGetUserMedia(null, gumCallback); - } - } - - function gumCallback(stream) { - connection.replaceTrack(stream, remoteUserId, isVideoTrack || session.video || session.screen); - } - }; - - connection.resetTrack = function(remoteUsersIds, isVideoTrack) { - if (!remoteUsersIds) { - remoteUsersIds = connection.getAllParticipants(); - } - - if (typeof remoteUsersIds == 'string') { - remoteUsersIds = [remoteUsersIds]; - } - - remoteUsersIds.forEach(function(participant) { - var peer = connection.peers[participant].peer; - - if ((typeof isVideoTrack === 'undefined' || isVideoTrack === true) && peer.lastVideoTrack) { - connection.replaceTrack(peer.lastVideoTrack, participant, true); - } - - if ((typeof isVideoTrack === 'undefined' || isVideoTrack === false) && peer.lastAudioTrack) { - connection.replaceTrack(peer.lastAudioTrack, participant, false); - } - }); - }; - - connection.renegotiate = function(remoteUserId) { - if (remoteUserId) { - mPeer.renegotiatePeer(remoteUserId); - return; - } - - connection.peers.getAllParticipants().forEach(function(participant) { - mPeer.renegotiatePeer(participant); - }); - }; - - connection.setStreamEndHandler = function(stream, isRemote) { - if (!stream || !stream.addEventListener) return; - - isRemote = !!isRemote; - - if (stream.alreadySetEndHandler) { - return; - } - stream.alreadySetEndHandler = true; - - var streamEndedEvent = 'ended'; - - if ('oninactive' in stream) { - streamEndedEvent = 'inactive'; - } - - stream.addEventListener(streamEndedEvent, function() { - if (stream.idInstance) { - currentUserMediaRequest.remove(stream.idInstance); - } - - if (!isRemote) { - // reset attachStreams - var streams = []; - connection.attachStreams.forEach(function(s) { - if (s.id != stream.id) { - streams.push(s); - } - }); - connection.attachStreams = streams; - } - - // connection.renegotiate(); - - var streamEvent = connection.streamEvents[stream.streamid]; - if (!streamEvent) { - streamEvent = { - stream: stream, - streamid: stream.streamid, - type: isRemote ? 'remote' : 'local', - userid: connection.userid, - extra: connection.extra, - mediaElement: connection.streamEvents[stream.streamid] ? connection.streamEvents[stream.streamid].mediaElement : null - }; - } - - if (isRemote && connection.peers[streamEvent.userid]) { - // reset remote "streams" - var peer = connection.peers[streamEvent.userid].peer; - var streams = []; - peer.getRemoteStreams().forEach(function(s) { - if (s.id != stream.id) { - streams.push(s); - } - }); - connection.peers[streamEvent.userid].streams = streams; - } - - if (streamEvent.userid === connection.userid && streamEvent.type === 'remote') { - return; - } - - if (connection.peersBackup[streamEvent.userid]) { - streamEvent.extra = connection.peersBackup[streamEvent.userid].extra; - } - - connection.onstreamended(streamEvent); - - delete connection.streamEvents[stream.streamid]; - }, false); - }; - - connection.onMediaError = function(error, constraints) { - if (!!connection.enableLogs) { - console.error(error, constraints); - } - }; - - connection.autoCloseEntireSession = false; - - connection.filesContainer = connection.videosContainer = document.body || document.documentElement; - connection.isInitiator = false; - - connection.shareFile = mPeer.shareFile; - if (typeof FileProgressBarHandler !== 'undefined') { - FileProgressBarHandler.handle(connection); - } - - if (typeof TranslationHandler !== 'undefined') { - TranslationHandler.handle(connection); - } - - connection.token = getRandomString; - - connection.onNewParticipant = function(participantId, userPreferences) { - connection.acceptParticipationRequest(participantId, userPreferences); - }; - - connection.acceptParticipationRequest = function(participantId, userPreferences) { - if (userPreferences.successCallback) { - userPreferences.successCallback(); - delete userPreferences.successCallback; - } - - mPeer.createNewPeer(participantId, userPreferences); - }; - - if (typeof StreamsHandler !== 'undefined') { - connection.StreamsHandler = StreamsHandler; - } - - connection.onleave = function(userid) {}; - - connection.invokeSelectFileDialog = function(callback) { - var selector = new FileSelector(); - selector.accept = '*.*'; - selector.selectSingleFile(callback); - }; - - connection.onmute = function(e) { - if (!e || !e.mediaElement) { - return; - } - - if (e.muteType === 'both' || e.muteType === 'video') { - e.mediaElement.src = null; - var paused = e.mediaElement.pause(); - if (typeof paused !== 'undefined') { - paused.then(function() { - e.mediaElement.poster = e.snapshot || 'https://cdn.webrtc-experiment.com/images/muted.png'; - }); - } else { - e.mediaElement.poster = e.snapshot || 'https://cdn.webrtc-experiment.com/images/muted.png'; - } - } else if (e.muteType === 'audio') { - e.mediaElement.muted = true; - } - }; - - connection.onunmute = function(e) { - if (!e || !e.mediaElement || !e.stream) { - return; - } - - if (e.unmuteType === 'both' || e.unmuteType === 'video') { - e.mediaElement.poster = null; - e.mediaElement.srcObject = e.stream; - e.mediaElement.play(); - } else if (e.unmuteType === 'audio') { - e.mediaElement.muted = false; - } - }; - - connection.onExtraDataUpdated = function(event) { - event.status = 'online'; - connection.onUserStatusChanged(event, true); - }; - - connection.getAllParticipants = function(sender) { - return connection.peers.getAllParticipants(sender); - }; - - if (typeof StreamsHandler !== 'undefined') { - StreamsHandler.onSyncNeeded = function(streamid, action, type) { - connection.peers.getAllParticipants().forEach(function(participant) { - mPeer.onNegotiationNeeded({ - streamid: streamid, - action: action, - streamSyncNeeded: true, - type: type || 'both' - }, participant); - }); - }; - } - - connection.connectSocket = function(callback) { - connectSocket(callback); - }; - - connection.closeSocket = function() { - try { - io.sockets = {}; - } catch (e) {}; - - if (!connection.socket) return; - - if (typeof connection.socket.disconnect === 'function') { - connection.socket.disconnect(); - } - - if (typeof connection.socket.resetProps === 'function') { - connection.socket.resetProps(); - } - - connection.socket = null; - }; - - connection.getSocket = function(callback) { - if (!callback && connection.enableLogs) { - console.warn('getSocket.callback paramter is required.'); - } - - callback = callback || function() {}; - - if (!connection.socket) { - connectSocket(function() { - callback(connection.socket); - }); - } else { - callback(connection.socket); - } - - return connection.socket; // callback is preferred over return-statement - }; - - connection.getRemoteStreams = mPeer.getRemoteStreams; - - var skipStreams = ['selectFirst', 'selectAll', 'forEach']; - - connection.streamEvents = { - selectFirst: function(options) { - return connection.streamEvents.selectAll(options)[0]; - }, - selectAll: function(options) { - if (!options) { - // default will always be all streams - options = { - local: true, - remote: true, - isScreen: true, - isAudio: true, - isVideo: true - }; - } - - if (options == 'local') { - options = { - local: true - }; - } - - if (options == 'remote') { - options = { - remote: true - }; - } - - if (options == 'screen') { - options = { - isScreen: true - }; - } - - if (options == 'audio') { - options = { - isAudio: true - }; - } - - if (options == 'video') { - options = { - isVideo: true - }; - } - - var streams = []; - Object.keys(connection.streamEvents).forEach(function(key) { - var event = connection.streamEvents[key]; - - if (skipStreams.indexOf(key) !== -1) return; - var ignore = true; - - if (options.local && event.type === 'local') { - ignore = false; - } - - if (options.remote && event.type === 'remote') { - ignore = false; - } - - if (options.isScreen && event.stream.isScreen) { - ignore = false; - } - - if (options.isVideo && event.stream.isVideo) { - ignore = false; - } - - if (options.isAudio && event.stream.isAudio) { - ignore = false; - } - - if (options.userid && event.userid === options.userid) { - ignore = false; - } - - if (ignore === false) { - streams.push(event); - } - }); - - return streams; - } - }; - - connection.socketURL = '/'; // generated via config.json - connection.socketMessageEvent = 'RTCMultiConnection-Message'; // generated via config.json - connection.socketCustomEvent = 'RTCMultiConnection-Custom-Message'; // generated via config.json - connection.DetectRTC = DetectRTC; - - connection.setCustomSocketEvent = function(customEvent) { - if (customEvent) { - connection.socketCustomEvent = customEvent; - } - - if (!connection.socket) { - return; - } - - connection.socket.emit('set-custom-socket-event-listener', connection.socketCustomEvent); - }; - - connection.getNumberOfBroadcastViewers = function(broadcastId, callback) { - if (!connection.socket || !broadcastId || !callback) return; - - connection.socket.emit('get-number-of-users-in-specific-broadcast', broadcastId, callback); - }; - - connection.onNumberOfBroadcastViewersUpdated = function(event) { - if (!connection.enableLogs || !connection.isInitiator) return; - console.info('Number of broadcast (', event.broadcastId, ') viewers', event.numberOfBroadcastViewers); - }; - - connection.onUserStatusChanged = function(event, dontWriteLogs) { - if (!!connection.enableLogs && !dontWriteLogs) { - console.info(event.userid, event.status); - } - }; - - connection.getUserMediaHandler = getUserMediaHandler; - connection.multiPeersHandler = mPeer; - connection.enableLogs = true; - connection.setCustomSocketHandler = function(customSocketHandler) { - if (typeof SocketConnection !== 'undefined') { - SocketConnection = customSocketHandler; - } - }; - - // default value should be 15k because [old]Firefox's receiving limit is 16k! - // however 64k works chrome-to-chrome - connection.chunkSize = 40 * 1000; - - connection.maxParticipantsAllowed = 1000; - - // eject or leave single user - connection.disconnectWith = mPeer.disconnectWith; - - // check if room exist on server - // we will pass roomid to the server and wait for callback (i.e. server's response) - connection.checkPresence = function(roomid, callback) { - roomid = roomid || connection.sessionid; - - if (SocketConnection.name === 'SSEConnection') { - SSEConnection.checkPresence(roomid, function(isRoomExist, _roomid, extra) { - if (!connection.socket) { - if (!isRoomExist) { - connection.userid = _roomid; - } - - connection.connectSocket(function() { - callback(isRoomExist, _roomid, extra); - }); - return; - } - callback(isRoomExist, _roomid); - }); - return; - } - - if (!connection.socket) { - connection.connectSocket(function() { - connection.checkPresence(roomid, callback); - }); - return; - } - - connection.socket.emit('check-presence', roomid + '', function(isRoomExist, _roomid, extra) { - if (connection.enableLogs) { - console.log('checkPresence.isRoomExist: ', isRoomExist, ' roomid: ', _roomid); - } - callback(isRoomExist, _roomid, extra); - }); - }; - - connection.onReadyForOffer = function(remoteUserId, userPreferences) { - connection.multiPeersHandler.createNewPeer(remoteUserId, userPreferences); - }; - - connection.setUserPreferences = function(userPreferences) { - if (connection.dontAttachStream) { - userPreferences.dontAttachLocalStream = true; - } - - if (connection.dontGetRemoteStream) { - userPreferences.dontGetRemoteStream = true; - } - - return userPreferences; - }; - - connection.updateExtraData = function() { - connection.socket.emit('extra-data-updated', connection.extra); - }; - - connection.enableScalableBroadcast = false; - connection.maxRelayLimitPerUser = 3; // each broadcast should serve only 3 users - - connection.dontCaptureUserMedia = false; - connection.dontAttachStream = false; - connection.dontGetRemoteStream = false; - - connection.onReConnecting = function(event) { - if (connection.enableLogs) { - console.info('ReConnecting with', event.userid, '...'); - } - }; - - connection.beforeAddingStream = function(stream) { - return stream; - }; - - connection.beforeRemovingStream = function(stream) { - return stream; - }; - - if (typeof isChromeExtensionAvailable !== 'undefined') { - connection.checkIfChromeExtensionAvailable = isChromeExtensionAvailable; - } - - if (typeof isFirefoxExtensionAvailable !== 'undefined') { - connection.checkIfChromeExtensionAvailable = isFirefoxExtensionAvailable; - } - - if (typeof getChromeExtensionStatus !== 'undefined') { - connection.getChromeExtensionStatus = getChromeExtensionStatus; - } - - connection.modifyScreenConstraints = function(screen_constraints) { - return screen_constraints; - }; - - connection.onPeerStateChanged = function(state) { - if (connection.enableLogs) { - if (state.iceConnectionState.search(/closed|failed/gi) !== -1) { - console.error('Peer connection is closed between you & ', state.userid, state.extra, 'state:', state.iceConnectionState); - } - } - }; - - connection.isOnline = true; - - listenEventHandler('online', function() { - connection.isOnline = true; - }); - - listenEventHandler('offline', function() { - connection.isOnline = false; - }); - - connection.isLowBandwidth = false; - if (navigator && navigator.connection && navigator.connection.type) { - connection.isLowBandwidth = navigator.connection.type.toString().toLowerCase().search(/wifi|cell/g) !== -1; - if (connection.isLowBandwidth) { - connection.bandwidth = { - audio: false, - video: false, - screen: false - }; - - if (connection.mediaConstraints.audio && connection.mediaConstraints.audio.optional && connection.mediaConstraints.audio.optional.length) { - var newArray = []; - connection.mediaConstraints.audio.optional.forEach(function(opt) { - if (typeof opt.bandwidth === 'undefined') { - newArray.push(opt); - } - }); - connection.mediaConstraints.audio.optional = newArray; - } - - if (connection.mediaConstraints.video && connection.mediaConstraints.video.optional && connection.mediaConstraints.video.optional.length) { - var newArray = []; - connection.mediaConstraints.video.optional.forEach(function(opt) { - if (typeof opt.bandwidth === 'undefined') { - newArray.push(opt); - } - }); - connection.mediaConstraints.video.optional = newArray; - } - } - } - - connection.getExtraData = function(remoteUserId, callback) { - if (!remoteUserId) throw 'remoteUserId is required.'; - - if (typeof callback === 'function') { - connection.socket.emit('get-remote-user-extra-data', remoteUserId, function(extra, remoteUserId, error) { - callback(extra, remoteUserId, error); - }); - return; - } - - if (!connection.peers[remoteUserId]) { - if (connection.peersBackup[remoteUserId]) { - return connection.peersBackup[remoteUserId].extra; - } - return {}; - } - - return connection.peers[remoteUserId].extra; - }; - - if (!!forceOptions.autoOpenOrJoin) { - connection.openOrJoin(connection.sessionid); - } - - connection.onUserIdAlreadyTaken = function(useridAlreadyTaken, yourNewUserId) { - // via #683 - connection.close(); - connection.closeSocket(); - - connection.isInitiator = false; - connection.userid = connection.token(); - - connection.join(connection.sessionid); - - if (connection.enableLogs) { - console.warn('Userid already taken.', useridAlreadyTaken, 'Your new userid:', connection.userid); - } - }; - - connection.trickleIce = true; - connection.version = '3.7.0'; - - connection.onSettingLocalDescription = function(event) { - if (connection.enableLogs) { - console.info('Set local description for remote user', event.userid); - } - }; - - connection.resetScreen = function() { - sourceId = null; - if (DetectRTC && DetectRTC.screen) { - delete DetectRTC.screen.sourceId; - } - - currentUserMediaRequest = { - streams: [], - mutex: false, - queueRequests: [] - }; - }; - - // if disabled, "event.mediaElement" for "onstream" will be NULL - connection.autoCreateMediaElement = true; - - // set password - connection.password = null; - - // set password - connection.setPassword = function(password, callback) { - callback = callback || function() {}; - if (connection.socket) { - connection.socket.emit('set-password', password, callback); - } else { - connection.password = password; - callback(true, connection.sessionid, null); - } - }; - - connection.onSocketDisconnect = function(event) { - if (connection.enableLogs) { - console.warn('socket.io connection is closed'); - } - }; - - connection.onSocketError = function(event) { - if (connection.enableLogs) { - console.warn('socket.io connection is failed'); - } - }; - - // error messages - connection.errors = { - ROOM_NOT_AVAILABLE: 'Room not available', - INVALID_PASSWORD: 'Invalid password', - USERID_NOT_AVAILABLE: 'User ID does not exist', - ROOM_PERMISSION_DENIED: 'Room permission denied', - ROOM_FULL: 'Room full', - DID_NOT_JOIN_ANY_ROOM: 'Did not join any room yet', - INVALID_SOCKET: 'Invalid socket', - PUBLIC_IDENTIFIER_MISSING: 'publicRoomIdentifier is required', - INVALID_ADMIN_CREDENTIAL: 'Invalid username or password attempted' - }; - })(this); - -}; - -if (typeof module !== 'undefined' /* && !!module.exports*/ ) { - module.exports = exports = RTCMultiConnection; -} - -if (typeof define === 'function' && define.amd) { - define('RTCMultiConnection', [], function() { - return RTCMultiConnection; - }); -} diff --git a/static/kevin-master/assets/js/RecordRTC.js b/static/kevin-master/assets/js/RecordRTC.js deleted file mode 100644 index be4c5a4..0000000 --- a/static/kevin-master/assets/js/RecordRTC.js +++ /dev/null @@ -1,6208 +0,0 @@ -'use strict'; - -// Last time updated: 2020-05-17 5:04:38 PM UTC - -// ________________ -// RecordRTC v5.6.1 - -// Open-Sourced: https://github.com/muaz-khan/RecordRTC - -// -------------------------------------------------- -// Muaz Khan - www.MuazKhan.com -// MIT License - www.WebRTC-Experiment.com/licence -// -------------------------------------------------- - -// ____________ -// RecordRTC.js - -/** - * {@link https://github.com/muaz-khan/RecordRTC|RecordRTC} is a WebRTC JavaScript library for audio/video as well as screen activity recording. It supports Chrome, Firefox, Opera, Android, and Microsoft Edge. Platforms: Linux, Mac and Windows. - * @summary Record audio, video or screen inside the browser. - * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} - * @author {@link https://MuazKhan.com|Muaz Khan} - * @typedef RecordRTC - * @class - * @example - * var recorder = RecordRTC(mediaStream or [arrayOfMediaStream], { - * type: 'video', // audio or video or gif or canvas - * recorderType: MediaStreamRecorder || CanvasRecorder || StereoAudioRecorder || Etc - * }); - * recorder.startRecording(); - * @see For further information: - * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} - * @param {MediaStream} mediaStream - Single media-stream object, array of media-streams, html-canvas-element, etc. - * @param {object} config - {type:"video", recorderType: MediaStreamRecorder, disableLogs: true, numberOfAudioChannels: 1, bufferSize: 0, sampleRate: 0, desiredSampRate: 16000, video: HTMLVideoElement, etc.} - */ - -function RecordRTC(mediaStream, config) { - if (!mediaStream) { - throw 'First parameter is required.'; - } - - config = config || { - type: 'video' - }; - - config = new RecordRTCConfiguration(mediaStream, config); - - // a reference to user's recordRTC object - var self = this; - - function startRecording(config2) { - if (!config.disableLogs) { - console.log('RecordRTC version: ', self.version); - } - - if (!!config2) { - // allow users to set options using startRecording method - // config2 is similar to main "config" object (second parameter over RecordRTC constructor) - config = new RecordRTCConfiguration(mediaStream, config2); - } - - if (!config.disableLogs) { - console.log('started recording ' + config.type + ' stream.'); - } - - if (mediaRecorder) { - mediaRecorder.clearRecordedData(); - mediaRecorder.record(); - - setState('recording'); - - if (self.recordingDuration) { - handleRecordingDuration(); - } - return self; - } - - initRecorder(function() { - if (self.recordingDuration) { - handleRecordingDuration(); - } - }); - - return self; - } - - function initRecorder(initCallback) { - if (initCallback) { - config.initCallback = function() { - initCallback(); - initCallback = config.initCallback = null; // recorder.initRecorder should be call-backed once. - }; - } - - var Recorder = new GetRecorderType(mediaStream, config); - - mediaRecorder = new Recorder(mediaStream, config); - mediaRecorder.record(); - - setState('recording'); - - if (!config.disableLogs) { - console.log('Initialized recorderType:', mediaRecorder.constructor.name, 'for output-type:', config.type); - } - } - - function stopRecording(callback) { - callback = callback || function() {}; - - if (!mediaRecorder) { - warningLog(); - return; - } - - if (self.state === 'paused') { - self.resumeRecording(); - - setTimeout(function() { - stopRecording(callback); - }, 1); - return; - } - - if (self.state !== 'recording' && !config.disableLogs) { - console.warn('Recording state should be: "recording", however current state is: ', self.state); - } - - if (!config.disableLogs) { - console.log('Stopped recording ' + config.type + ' stream.'); - } - - if (config.type !== 'gif') { - mediaRecorder.stop(_callback); - } else { - mediaRecorder.stop(); - _callback(); - } - - setState('stopped'); - - function _callback(__blob) { - if (!mediaRecorder) { - if (typeof callback.call === 'function') { - callback.call(self, ''); - } else { - callback(''); - } - return; - } - - Object.keys(mediaRecorder).forEach(function(key) { - if (typeof mediaRecorder[key] === 'function') { - return; - } - - self[key] = mediaRecorder[key]; - }); - - var blob = mediaRecorder.blob; - - if (!blob) { - if (__blob) { - mediaRecorder.blob = blob = __blob; - } else { - throw 'Recording failed.'; - } - } - - if (blob && !config.disableLogs) { - console.log(blob.type, '->', bytesToSize(blob.size)); - } - - if (callback) { - var url; - - try { - url = URL.createObjectURL(blob); - } catch (e) {} - - if (typeof callback.call === 'function') { - callback.call(self, url); - } else { - callback(url); - } - } - - if (!config.autoWriteToDisk) { - return; - } - - getDataURL(function(dataURL) { - var parameter = {}; - parameter[config.type + 'Blob'] = dataURL; - DiskStorage.Store(parameter); - }); - } - } - - function pauseRecording() { - if (!mediaRecorder) { - warningLog(); - return; - } - - if (self.state !== 'recording') { - if (!config.disableLogs) { - console.warn('Unable to pause the recording. Recording state: ', self.state); - } - return; - } - - setState('paused'); - - mediaRecorder.pause(); - - if (!config.disableLogs) { - console.log('Paused recording.'); - } - } - - function resumeRecording() { - if (!mediaRecorder) { - warningLog(); - return; - } - - if (self.state !== 'paused') { - if (!config.disableLogs) { - console.warn('Unable to resume the recording. Recording state: ', self.state); - } - return; - } - - setState('recording'); - - // not all libs have this method yet - mediaRecorder.resume(); - - if (!config.disableLogs) { - console.log('Resumed recording.'); - } - } - - function readFile(_blob) { - postMessage(new FileReaderSync().readAsDataURL(_blob)); - } - - function getDataURL(callback, _mediaRecorder) { - if (!callback) { - throw 'Pass a callback function over getDataURL.'; - } - - var blob = _mediaRecorder ? _mediaRecorder.blob : (mediaRecorder || {}).blob; - - if (!blob) { - if (!config.disableLogs) { - console.warn('Blob encoder did not finish its job yet.'); - } - - setTimeout(function() { - getDataURL(callback, _mediaRecorder); - }, 1000); - return; - } - - if (typeof Worker !== 'undefined' && !navigator.mozGetUserMedia) { - var webWorker = processInWebWorker(readFile); - - webWorker.onmessage = function(event) { - callback(event.data); - }; - - webWorker.postMessage(blob); - } else { - var reader = new FileReader(); - reader.readAsDataURL(blob); - reader.onload = function(event) { - callback(event.target.result); - }; - } - - function processInWebWorker(_function) { - try { - var blob = URL.createObjectURL(new Blob([_function.toString(), - 'this.onmessage = function (eee) {' + _function.name + '(eee.data);}' - ], { - type: 'application/javascript' - })); - - var worker = new Worker(blob); - URL.revokeObjectURL(blob); - return worker; - } catch (e) {} - } - } - - function handleRecordingDuration(counter) { - counter = counter || 0; - - if (self.state === 'paused') { - setTimeout(function() { - handleRecordingDuration(counter); - }, 1000); - return; - } - - if (self.state === 'stopped') { - return; - } - - if (counter >= self.recordingDuration) { - stopRecording(self.onRecordingStopped); - return; - } - - counter += 1000; // 1-second - - setTimeout(function() { - handleRecordingDuration(counter); - }, 1000); - } - - function setState(state) { - if (!self) { - return; - } - - self.state = state; - - if (typeof self.onStateChanged.call === 'function') { - self.onStateChanged.call(self, state); - } else { - self.onStateChanged(state); - } - } - - var WARNING = 'It seems that recorder is destroyed or "startRecording" is not invoked for ' + config.type + ' recorder.'; - - function warningLog() { - if (config.disableLogs === true) { - return; - } - - console.warn(WARNING); - } - - var mediaRecorder; - - var returnObject = { - /** - * This method starts the recording. - * @method - * @memberof RecordRTC - * @instance - * @example - * var recorder = RecordRTC(mediaStream, { - * type: 'video' - * }); - * recorder.startRecording(); - */ - startRecording: startRecording, - - /** - * This method stops the recording. It is strongly recommended to get "blob" or "URI" inside the callback to make sure all recorders finished their job. - * @param {function} callback - Callback to get the recorded blob. - * @method - * @memberof RecordRTC - * @instance - * @example - * recorder.stopRecording(function() { - * // use either "this" or "recorder" object; both are identical - * video.src = this.toURL(); - * var blob = this.getBlob(); - * }); - */ - stopRecording: stopRecording, - - /** - * This method pauses the recording. You can resume recording using "resumeRecording" method. - * @method - * @memberof RecordRTC - * @instance - * @todo Firefox is unable to pause the recording. Fix it. - * @example - * recorder.pauseRecording(); // pause the recording - * recorder.resumeRecording(); // resume again - */ - pauseRecording: pauseRecording, - - /** - * This method resumes the recording. - * @method - * @memberof RecordRTC - * @instance - * @example - * recorder.pauseRecording(); // first of all, pause the recording - * recorder.resumeRecording(); // now resume it - */ - resumeRecording: resumeRecording, - - /** - * This method initializes the recording. - * @method - * @memberof RecordRTC - * @instance - * @todo This method should be deprecated. - * @example - * recorder.initRecorder(); - */ - initRecorder: initRecorder, - - /** - * Ask RecordRTC to auto-stop the recording after 5 minutes. - * @method - * @memberof RecordRTC - * @instance - * @example - * var fiveMinutes = 5 * 1000 * 60; - * recorder.setRecordingDuration(fiveMinutes, function() { - * var blob = this.getBlob(); - * video.src = this.toURL(); - * }); - * - * // or otherwise - * recorder.setRecordingDuration(fiveMinutes).onRecordingStopped(function() { - * var blob = this.getBlob(); - * video.src = this.toURL(); - * }); - */ - setRecordingDuration: function(recordingDuration, callback) { - if (typeof recordingDuration === 'undefined') { - throw 'recordingDuration is required.'; - } - - if (typeof recordingDuration !== 'number') { - throw 'recordingDuration must be a number.'; - } - - self.recordingDuration = recordingDuration; - self.onRecordingStopped = callback || function() {}; - - return { - onRecordingStopped: function(callback) { - self.onRecordingStopped = callback; - } - }; - }, - - /** - * This method can be used to clear/reset all the recorded data. - * @method - * @memberof RecordRTC - * @instance - * @todo Figure out the difference between "reset" and "clearRecordedData" methods. - * @example - * recorder.clearRecordedData(); - */ - clearRecordedData: function() { - if (!mediaRecorder) { - warningLog(); - return; - } - - mediaRecorder.clearRecordedData(); - - if (!config.disableLogs) { - console.log('Cleared old recorded data.'); - } - }, - - /** - * Get the recorded blob. Use this method inside the "stopRecording" callback. - * @method - * @memberof RecordRTC - * @instance - * @example - * recorder.stopRecording(function() { - * var blob = this.getBlob(); - * - * var file = new File([blob], 'filename.webm', { - * type: 'video/webm' - * }); - * - * var formData = new FormData(); - * formData.append('file', file); // upload "File" object rather than a "Blob" - * uploadToServer(formData); - * }); - * @returns {Blob} Returns recorded data as "Blob" object. - */ - getBlob: function() { - if (!mediaRecorder) { - warningLog(); - return; - } - - return mediaRecorder.blob; - }, - - /** - * Get data-URI instead of Blob. - * @param {function} callback - Callback to get the Data-URI. - * @method - * @memberof RecordRTC - * @instance - * @example - * recorder.stopRecording(function() { - * recorder.getDataURL(function(dataURI) { - * video.src = dataURI; - * }); - * }); - */ - getDataURL: getDataURL, - - /** - * Get virtual/temporary URL. Usage of this URL is limited to current tab. - * @method - * @memberof RecordRTC - * @instance - * @example - * recorder.stopRecording(function() { - * video.src = this.toURL(); - * }); - * @returns {String} Returns a virtual/temporary URL for the recorded "Blob". - */ - toURL: function() { - if (!mediaRecorder) { - warningLog(); - return; - } - - return URL.createObjectURL(mediaRecorder.blob); - }, - - /** - * Get internal recording object (i.e. internal module) e.g. MutliStreamRecorder, MediaStreamRecorder, StereoAudioRecorder or WhammyRecorder etc. - * @method - * @memberof RecordRTC - * @instance - * @example - * var internalRecorder = recorder.getInternalRecorder(); - * if(internalRecorder instanceof MultiStreamRecorder) { - * internalRecorder.addStreams([newAudioStream]); - * internalRecorder.resetVideoStreams([screenStream]); - * } - * @returns {Object} Returns internal recording object. - */ - getInternalRecorder: function() { - return mediaRecorder; - }, - - /** - * Invoke save-as dialog to save the recorded blob into your disk. - * @param {string} fileName - Set your own file name. - * @method - * @memberof RecordRTC - * @instance - * @example - * recorder.stopRecording(function() { - * this.save('file-name'); - * - * // or manually: - * invokeSaveAsDialog(this.getBlob(), 'filename.webm'); - * }); - */ - save: function(fileName) { - if (!mediaRecorder) { - warningLog(); - return; - } - - invokeSaveAsDialog(mediaRecorder.blob, fileName); - }, - - /** - * This method gets a blob from indexed-DB storage. - * @param {function} callback - Callback to get the recorded blob. - * @method - * @memberof RecordRTC - * @instance - * @example - * recorder.getFromDisk(function(dataURL) { - * video.src = dataURL; - * }); - */ - getFromDisk: function(callback) { - if (!mediaRecorder) { - warningLog(); - return; - } - - RecordRTC.getFromDisk(config.type, callback); - }, - - /** - * This method appends an array of webp images to the recorded video-blob. It takes an "array" object. - * @type {Array.} - * @param {Array} arrayOfWebPImages - Array of webp images. - * @method - * @memberof RecordRTC - * @instance - * @todo This method should be deprecated. - * @example - * var arrayOfWebPImages = []; - * arrayOfWebPImages.push({ - * duration: index, - * image: 'data:image/webp;base64,...' - * }); - * recorder.setAdvertisementArray(arrayOfWebPImages); - */ - setAdvertisementArray: function(arrayOfWebPImages) { - config.advertisement = []; - - var length = arrayOfWebPImages.length; - for (var i = 0; i < length; i++) { - config.advertisement.push({ - duration: i, - image: arrayOfWebPImages[i] - }); - } - }, - - /** - * It is equivalent to "recorder.getBlob()" method. Usage of "getBlob" is recommended, though. - * @property {Blob} blob - Recorded Blob can be accessed using this property. - * @memberof RecordRTC - * @instance - * @readonly - * @example - * recorder.stopRecording(function() { - * var blob = this.blob; - * - * // below one is recommended - * var blob = this.getBlob(); - * }); - */ - blob: null, - - /** - * This works only with {recorderType:StereoAudioRecorder}. Use this property on "stopRecording" to verify the encoder's sample-rates. - * @property {number} bufferSize - Buffer-size used to encode the WAV container - * @memberof RecordRTC - * @instance - * @readonly - * @example - * recorder.stopRecording(function() { - * alert('Recorder used this buffer-size: ' + this.bufferSize); - * }); - */ - bufferSize: 0, - - /** - * This works only with {recorderType:StereoAudioRecorder}. Use this property on "stopRecording" to verify the encoder's sample-rates. - * @property {number} sampleRate - Sample-rates used to encode the WAV container - * @memberof RecordRTC - * @instance - * @readonly - * @example - * recorder.stopRecording(function() { - * alert('Recorder used these sample-rates: ' + this.sampleRate); - * }); - */ - sampleRate: 0, - - /** - * {recorderType:StereoAudioRecorder} returns ArrayBuffer object. - * @property {ArrayBuffer} buffer - Audio ArrayBuffer, supported only in Chrome. - * @memberof RecordRTC - * @instance - * @readonly - * @example - * recorder.stopRecording(function() { - * var arrayBuffer = this.buffer; - * alert(arrayBuffer.byteLength); - * }); - */ - buffer: null, - - /** - * This method resets the recorder. So that you can reuse single recorder instance many times. - * @method - * @memberof RecordRTC - * @instance - * @example - * recorder.reset(); - * recorder.startRecording(); - */ - reset: function() { - if (self.state === 'recording' && !config.disableLogs) { - console.warn('Stop an active recorder.'); - } - - if (mediaRecorder && typeof mediaRecorder.clearRecordedData === 'function') { - mediaRecorder.clearRecordedData(); - } - mediaRecorder = null; - setState('inactive'); - self.blob = null; - }, - - /** - * This method is called whenever recorder's state changes. Use this as an "event". - * @property {String} state - A recorder's state can be: recording, paused, stopped or inactive. - * @method - * @memberof RecordRTC - * @instance - * @example - * recorder.onStateChanged = function(state) { - * console.log('Recorder state: ', state); - * }; - */ - onStateChanged: function(state) { - if (!config.disableLogs) { - console.log('Recorder state changed:', state); - } - }, - - /** - * A recorder can have inactive, recording, paused or stopped states. - * @property {String} state - A recorder's state can be: recording, paused, stopped or inactive. - * @memberof RecordRTC - * @static - * @readonly - * @example - * // this looper function will keep you updated about the recorder's states. - * (function looper() { - * document.querySelector('h1').innerHTML = 'Recorder\'s state is: ' + recorder.state; - * if(recorder.state === 'stopped') return; // ignore+stop - * setTimeout(looper, 1000); // update after every 3-seconds - * })(); - * recorder.startRecording(); - */ - state: 'inactive', - - /** - * Get recorder's readonly state. - * @method - * @memberof RecordRTC - * @example - * var state = recorder.getState(); - * @returns {String} Returns recording state. - */ - getState: function() { - return self.state; - }, - - /** - * Destroy RecordRTC instance. Clear all recorders and objects. - * @method - * @memberof RecordRTC - * @example - * recorder.destroy(); - */ - destroy: function() { - var disableLogsCache = config.disableLogs; - - config = { - disableLogs: true - }; - self.reset(); - setState('destroyed'); - returnObject = self = null; - - if (Storage.AudioContextConstructor) { - Storage.AudioContextConstructor.close(); - Storage.AudioContextConstructor = null; - } - - config.disableLogs = disableLogsCache; - - if (!config.disableLogs) { - console.log('RecordRTC is destroyed.'); - } - }, - - /** - * RecordRTC version number - * @property {String} version - Release version number. - * @memberof RecordRTC - * @static - * @readonly - * @example - * alert(recorder.version); - */ - version: '5.6.1' - }; - - if (!this) { - self = returnObject; - return returnObject; - } - - // if someone wants to use RecordRTC with the "new" keyword. - for (var prop in returnObject) { - this[prop] = returnObject[prop]; - } - - self = this; - - return returnObject; -} - -RecordRTC.version = '5.6.1'; - -if (typeof module !== 'undefined' /* && !!module.exports*/ ) { - module.exports = RecordRTC; -} - -if (typeof define === 'function' && define.amd) { - define('RecordRTC', [], function() { - return RecordRTC; - }); -} - -RecordRTC.getFromDisk = function(type, callback) { - if (!callback) { - throw 'callback is mandatory.'; - } - - console.log('Getting recorded ' + (type === 'all' ? 'blobs' : type + ' blob ') + ' from disk!'); - DiskStorage.Fetch(function(dataURL, _type) { - if (type !== 'all' && _type === type + 'Blob' && callback) { - callback(dataURL); - } - - if (type === 'all' && callback) { - callback(dataURL, _type.replace('Blob', '')); - } - }); -}; - -/** - * This method can be used to store recorded blobs into IndexedDB storage. - * @param {object} options - {audio: Blob, video: Blob, gif: Blob} - * @method - * @memberof RecordRTC - * @example - * RecordRTC.writeToDisk({ - * audio: audioBlob, - * video: videoBlob, - * gif : gifBlob - * }); - */ -RecordRTC.writeToDisk = function(options) { - console.log('Writing recorded blob(s) to disk!'); - options = options || {}; - if (options.audio && options.video && options.gif) { - options.audio.getDataURL(function(audioDataURL) { - options.video.getDataURL(function(videoDataURL) { - options.gif.getDataURL(function(gifDataURL) { - DiskStorage.Store({ - audioBlob: audioDataURL, - videoBlob: videoDataURL, - gifBlob: gifDataURL - }); - }); - }); - }); - } else if (options.audio && options.video) { - options.audio.getDataURL(function(audioDataURL) { - options.video.getDataURL(function(videoDataURL) { - DiskStorage.Store({ - audioBlob: audioDataURL, - videoBlob: videoDataURL - }); - }); - }); - } else if (options.audio && options.gif) { - options.audio.getDataURL(function(audioDataURL) { - options.gif.getDataURL(function(gifDataURL) { - DiskStorage.Store({ - audioBlob: audioDataURL, - gifBlob: gifDataURL - }); - }); - }); - } else if (options.video && options.gif) { - options.video.getDataURL(function(videoDataURL) { - options.gif.getDataURL(function(gifDataURL) { - DiskStorage.Store({ - videoBlob: videoDataURL, - gifBlob: gifDataURL - }); - }); - }); - } else if (options.audio) { - options.audio.getDataURL(function(audioDataURL) { - DiskStorage.Store({ - audioBlob: audioDataURL - }); - }); - } else if (options.video) { - options.video.getDataURL(function(videoDataURL) { - DiskStorage.Store({ - videoBlob: videoDataURL - }); - }); - } else if (options.gif) { - options.gif.getDataURL(function(gifDataURL) { - DiskStorage.Store({ - gifBlob: gifDataURL - }); - }); - } -}; - -// __________________________ -// RecordRTC-Configuration.js - -/** - * {@link RecordRTCConfiguration} is an inner/private helper for {@link RecordRTC}. - * @summary It configures the 2nd parameter passed over {@link RecordRTC} and returns a valid "config" object. - * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} - * @author {@link https://MuazKhan.com|Muaz Khan} - * @typedef RecordRTCConfiguration - * @class - * @example - * var options = RecordRTCConfiguration(mediaStream, options); - * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} - * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API. - * @param {object} config - {type:"video", disableLogs: true, numberOfAudioChannels: 1, bufferSize: 0, sampleRate: 0, video: HTMLVideoElement, getNativeBlob:true, etc.} - */ - -function RecordRTCConfiguration(mediaStream, config) { - if (!config.recorderType && !config.type) { - if (!!config.audio && !!config.video) { - config.type = 'video'; - } else if (!!config.audio && !config.video) { - config.type = 'audio'; - } - } - - if (config.recorderType && !config.type) { - if (config.recorderType === WhammyRecorder || config.recorderType === CanvasRecorder || (typeof WebAssemblyRecorder !== 'undefined' && config.recorderType === WebAssemblyRecorder)) { - config.type = 'video'; - } else if (config.recorderType === GifRecorder) { - config.type = 'gif'; - } else if (config.recorderType === StereoAudioRecorder) { - config.type = 'audio'; - } else if (config.recorderType === MediaStreamRecorder) { - if (getTracks(mediaStream, 'audio').length && getTracks(mediaStream, 'video').length) { - config.type = 'video'; - } else if (!getTracks(mediaStream, 'audio').length && getTracks(mediaStream, 'video').length) { - config.type = 'video'; - } else if (getTracks(mediaStream, 'audio').length && !getTracks(mediaStream, 'video').length) { - config.type = 'audio'; - } else { - // config.type = 'UnKnown'; - } - } - } - - if (typeof MediaStreamRecorder !== 'undefined' && typeof MediaRecorder !== 'undefined' && 'requestData' in MediaRecorder.prototype) { - if (!config.mimeType) { - config.mimeType = 'video/webm'; - } - - if (!config.type) { - config.type = config.mimeType.split('/')[0]; - } - - if (!config.bitsPerSecond) { - // config.bitsPerSecond = 128000; - } - } - - // consider default type=audio - if (!config.type) { - if (config.mimeType) { - config.type = config.mimeType.split('/')[0]; - } - if (!config.type) { - config.type = 'audio'; - } - } - - return config; -} - -// __________________ -// GetRecorderType.js - -/** - * {@link GetRecorderType} is an inner/private helper for {@link RecordRTC}. - * @summary It returns best recorder-type available for your browser. - * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} - * @author {@link https://MuazKhan.com|Muaz Khan} - * @typedef GetRecorderType - * @class - * @example - * var RecorderType = GetRecorderType(options); - * var recorder = new RecorderType(options); - * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} - * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API. - * @param {object} config - {type:"video", disableLogs: true, numberOfAudioChannels: 1, bufferSize: 0, sampleRate: 0, video: HTMLVideoElement, etc.} - */ - -function GetRecorderType(mediaStream, config) { - var recorder; - - // StereoAudioRecorder can work with all three: Edge, Firefox and Chrome - // todo: detect if it is Edge, then auto use: StereoAudioRecorder - if (isChrome || isEdge || isOpera) { - // Media Stream Recording API has not been implemented in chrome yet; - // That's why using WebAudio API to record stereo audio in WAV format - recorder = StereoAudioRecorder; - } - - if (typeof MediaRecorder !== 'undefined' && 'requestData' in MediaRecorder.prototype && !isChrome) { - recorder = MediaStreamRecorder; - } - - // video recorder (in WebM format) - if (config.type === 'video' && (isChrome || isOpera)) { - recorder = WhammyRecorder; - - if (typeof WebAssemblyRecorder !== 'undefined' && typeof ReadableStream !== 'undefined') { - recorder = WebAssemblyRecorder; - } - } - - // video recorder (in Gif format) - if (config.type === 'gif') { - recorder = GifRecorder; - } - - // html2canvas recording! - if (config.type === 'canvas') { - recorder = CanvasRecorder; - } - - if (isMediaRecorderCompatible() && recorder !== CanvasRecorder && recorder !== GifRecorder && typeof MediaRecorder !== 'undefined' && 'requestData' in MediaRecorder.prototype) { - if (getTracks(mediaStream, 'video').length || getTracks(mediaStream, 'audio').length) { - // audio-only recording - if (config.type === 'audio') { - if (typeof MediaRecorder.isTypeSupported === 'function' && MediaRecorder.isTypeSupported('audio/webm')) { - recorder = MediaStreamRecorder; - } - // else recorder = StereoAudioRecorder; - } else { - // video or screen tracks - if (typeof MediaRecorder.isTypeSupported === 'function' && MediaRecorder.isTypeSupported('video/webm')) { - recorder = MediaStreamRecorder; - } - } - } - } - - if (mediaStream instanceof Array && mediaStream.length) { - recorder = MultiStreamRecorder; - } - - if (config.recorderType) { - recorder = config.recorderType; - } - - if (!config.disableLogs && !!recorder && !!recorder.name) { - console.log('Using recorderType:', recorder.name || recorder.constructor.name); - } - - if (!recorder && isSafari) { - recorder = MediaStreamRecorder; - } - - return recorder; -} - -// _____________ -// MRecordRTC.js - -/** - * MRecordRTC runs on top of {@link RecordRTC} to bring multiple recordings in a single place, by providing simple API. - * @summary MRecordRTC stands for "Multiple-RecordRTC". - * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} - * @author {@link https://MuazKhan.com|Muaz Khan} - * @typedef MRecordRTC - * @class - * @example - * var recorder = new MRecordRTC(); - * recorder.addStream(MediaStream); - * recorder.mediaType = { - * audio: true, // or StereoAudioRecorder or MediaStreamRecorder - * video: true, // or WhammyRecorder or MediaStreamRecorder or WebAssemblyRecorder or CanvasRecorder - * gif: true // or GifRecorder - * }; - * // mimeType is optional and should be set only in advance cases. - * recorder.mimeType = { - * audio: 'audio/wav', - * video: 'video/webm', - * gif: 'image/gif' - * }; - * recorder.startRecording(); - * @see For further information: - * @see {@link https://github.com/muaz-khan/RecordRTC/tree/master/MRecordRTC|MRecordRTC Source Code} - * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API. - * @requires {@link RecordRTC} - */ - -function MRecordRTC(mediaStream) { - - /** - * This method attaches MediaStream object to {@link MRecordRTC}. - * @param {MediaStream} mediaStream - A MediaStream object, either fetched using getUserMedia API, or generated using captureStreamUntilEnded or WebAudio API. - * @method - * @memberof MRecordRTC - * @example - * recorder.addStream(MediaStream); - */ - this.addStream = function(_mediaStream) { - if (_mediaStream) { - mediaStream = _mediaStream; - } - }; - - /** - * This property can be used to set the recording type e.g. audio, or video, or gif, or canvas. - * @property {object} mediaType - {audio: true, video: true, gif: true} - * @memberof MRecordRTC - * @example - * var recorder = new MRecordRTC(); - * recorder.mediaType = { - * audio: true, // TRUE or StereoAudioRecorder or MediaStreamRecorder - * video: true, // TRUE or WhammyRecorder or MediaStreamRecorder or WebAssemblyRecorder or CanvasRecorder - * gif : true // TRUE or GifRecorder - * }; - */ - this.mediaType = { - audio: true, - video: true - }; - - /** - * This method starts recording. - * @method - * @memberof MRecordRTC - * @example - * recorder.startRecording(); - */ - this.startRecording = function() { - var mediaType = this.mediaType; - var recorderType; - var mimeType = this.mimeType || { - audio: null, - video: null, - gif: null - }; - - if (typeof mediaType.audio !== 'function' && isMediaRecorderCompatible() && !getTracks(mediaStream, 'audio').length) { - mediaType.audio = false; - } - - if (typeof mediaType.video !== 'function' && isMediaRecorderCompatible() && !getTracks(mediaStream, 'video').length) { - mediaType.video = false; - } - - if (typeof mediaType.gif !== 'function' && isMediaRecorderCompatible() && !getTracks(mediaStream, 'video').length) { - mediaType.gif = false; - } - - if (!mediaType.audio && !mediaType.video && !mediaType.gif) { - throw 'MediaStream must have either audio or video tracks.'; - } - - if (!!mediaType.audio) { - recorderType = null; - if (typeof mediaType.audio === 'function') { - recorderType = mediaType.audio; - } - - this.audioRecorder = new RecordRTC(mediaStream, { - type: 'audio', - bufferSize: this.bufferSize, - sampleRate: this.sampleRate, - numberOfAudioChannels: this.numberOfAudioChannels || 2, - disableLogs: this.disableLogs, - recorderType: recorderType, - mimeType: mimeType.audio, - timeSlice: this.timeSlice, - onTimeStamp: this.onTimeStamp - }); - - if (!mediaType.video) { - this.audioRecorder.startRecording(); - } - } - - if (!!mediaType.video) { - recorderType = null; - if (typeof mediaType.video === 'function') { - recorderType = mediaType.video; - } - - var newStream = mediaStream; - - if (isMediaRecorderCompatible() && !!mediaType.audio && typeof mediaType.audio === 'function') { - var videoTrack = getTracks(mediaStream, 'video')[0]; - - if (isFirefox) { - newStream = new MediaStream(); - newStream.addTrack(videoTrack); - - if (recorderType && recorderType === WhammyRecorder) { - // Firefox does NOT supports webp-encoding yet - // But Firefox do supports WebAssemblyRecorder - recorderType = MediaStreamRecorder; - } - } else { - newStream = new MediaStream(); - newStream.addTrack(videoTrack); - } - } - - this.videoRecorder = new RecordRTC(newStream, { - type: 'video', - video: this.video, - canvas: this.canvas, - frameInterval: this.frameInterval || 10, - disableLogs: this.disableLogs, - recorderType: recorderType, - mimeType: mimeType.video, - timeSlice: this.timeSlice, - onTimeStamp: this.onTimeStamp, - workerPath: this.workerPath, - webAssemblyPath: this.webAssemblyPath, - frameRate: this.frameRate, // used by WebAssemblyRecorder; values: usually 30; accepts any. - bitrate: this.bitrate // used by WebAssemblyRecorder; values: 0 to 1000+ - }); - - if (!mediaType.audio) { - this.videoRecorder.startRecording(); - } - } - - if (!!mediaType.audio && !!mediaType.video) { - var self = this; - - var isSingleRecorder = isMediaRecorderCompatible() === true; - - if (mediaType.audio instanceof StereoAudioRecorder && !!mediaType.video) { - isSingleRecorder = false; - } else if (mediaType.audio !== true && mediaType.video !== true && mediaType.audio !== mediaType.video) { - isSingleRecorder = false; - } - - if (isSingleRecorder === true) { - self.audioRecorder = null; - self.videoRecorder.startRecording(); - } else { - self.videoRecorder.initRecorder(function() { - self.audioRecorder.initRecorder(function() { - // Both recorders are ready to record things accurately - self.videoRecorder.startRecording(); - self.audioRecorder.startRecording(); - }); - }); - } - } - - if (!!mediaType.gif) { - recorderType = null; - if (typeof mediaType.gif === 'function') { - recorderType = mediaType.gif; - } - this.gifRecorder = new RecordRTC(mediaStream, { - type: 'gif', - frameRate: this.frameRate || 200, - quality: this.quality || 10, - disableLogs: this.disableLogs, - recorderType: recorderType, - mimeType: mimeType.gif - }); - this.gifRecorder.startRecording(); - } - }; - - /** - * This method stops recording. - * @param {function} callback - Callback function is invoked when all encoders finished their jobs. - * @method - * @memberof MRecordRTC - * @example - * recorder.stopRecording(function(recording){ - * var audioBlob = recording.audio; - * var videoBlob = recording.video; - * var gifBlob = recording.gif; - * }); - */ - this.stopRecording = function(callback) { - callback = callback || function() {}; - - if (this.audioRecorder) { - this.audioRecorder.stopRecording(function(blobURL) { - callback(blobURL, 'audio'); - }); - } - - if (this.videoRecorder) { - this.videoRecorder.stopRecording(function(blobURL) { - callback(blobURL, 'video'); - }); - } - - if (this.gifRecorder) { - this.gifRecorder.stopRecording(function(blobURL) { - callback(blobURL, 'gif'); - }); - } - }; - - /** - * This method pauses recording. - * @method - * @memberof MRecordRTC - * @example - * recorder.pauseRecording(); - */ - this.pauseRecording = function() { - if (this.audioRecorder) { - this.audioRecorder.pauseRecording(); - } - - if (this.videoRecorder) { - this.videoRecorder.pauseRecording(); - } - - if (this.gifRecorder) { - this.gifRecorder.pauseRecording(); - } - }; - - /** - * This method resumes recording. - * @method - * @memberof MRecordRTC - * @example - * recorder.resumeRecording(); - */ - this.resumeRecording = function() { - if (this.audioRecorder) { - this.audioRecorder.resumeRecording(); - } - - if (this.videoRecorder) { - this.videoRecorder.resumeRecording(); - } - - if (this.gifRecorder) { - this.gifRecorder.resumeRecording(); - } - }; - - /** - * This method can be used to manually get all recorded blobs. - * @param {function} callback - All recorded blobs are passed back to the "callback" function. - * @method - * @memberof MRecordRTC - * @example - * recorder.getBlob(function(recording){ - * var audioBlob = recording.audio; - * var videoBlob = recording.video; - * var gifBlob = recording.gif; - * }); - * // or - * var audioBlob = recorder.getBlob().audio; - * var videoBlob = recorder.getBlob().video; - */ - this.getBlob = function(callback) { - var output = {}; - - if (this.audioRecorder) { - output.audio = this.audioRecorder.getBlob(); - } - - if (this.videoRecorder) { - output.video = this.videoRecorder.getBlob(); - } - - if (this.gifRecorder) { - output.gif = this.gifRecorder.getBlob(); - } - - if (callback) { - callback(output); - } - - return output; - }; - - /** - * Destroy all recorder instances. - * @method - * @memberof MRecordRTC - * @example - * recorder.destroy(); - */ - this.destroy = function() { - if (this.audioRecorder) { - this.audioRecorder.destroy(); - this.audioRecorder = null; - } - - if (this.videoRecorder) { - this.videoRecorder.destroy(); - this.videoRecorder = null; - } - - if (this.gifRecorder) { - this.gifRecorder.destroy(); - this.gifRecorder = null; - } - }; - - /** - * This method can be used to manually get all recorded blobs' DataURLs. - * @param {function} callback - All recorded blobs' DataURLs are passed back to the "callback" function. - * @method - * @memberof MRecordRTC - * @example - * recorder.getDataURL(function(recording){ - * var audioDataURL = recording.audio; - * var videoDataURL = recording.video; - * var gifDataURL = recording.gif; - * }); - */ - this.getDataURL = function(callback) { - this.getBlob(function(blob) { - if (blob.audio && blob.video) { - getDataURL(blob.audio, function(_audioDataURL) { - getDataURL(blob.video, function(_videoDataURL) { - callback({ - audio: _audioDataURL, - video: _videoDataURL - }); - }); - }); - } else if (blob.audio) { - getDataURL(blob.audio, function(_audioDataURL) { - callback({ - audio: _audioDataURL - }); - }); - } else if (blob.video) { - getDataURL(blob.video, function(_videoDataURL) { - callback({ - video: _videoDataURL - }); - }); - } - }); - - function getDataURL(blob, callback00) { - if (typeof Worker !== 'undefined') { - var webWorker = processInWebWorker(function readFile(_blob) { - postMessage(new FileReaderSync().readAsDataURL(_blob)); - }); - - webWorker.onmessage = function(event) { - callback00(event.data); - }; - - webWorker.postMessage(blob); - } else { - var reader = new FileReader(); - reader.readAsDataURL(blob); - reader.onload = function(event) { - callback00(event.target.result); - }; - } - } - - function processInWebWorker(_function) { - var blob = URL.createObjectURL(new Blob([_function.toString(), - 'this.onmessage = function (eee) {' + _function.name + '(eee.data);}' - ], { - type: 'application/javascript' - })); - - var worker = new Worker(blob); - var url; - if (typeof URL !== 'undefined') { - url = URL; - } else if (typeof webkitURL !== 'undefined') { - url = webkitURL; - } else { - throw 'Neither URL nor webkitURL detected.'; - } - url.revokeObjectURL(blob); - return worker; - } - }; - - /** - * This method can be used to ask {@link MRecordRTC} to write all recorded blobs into IndexedDB storage. - * @method - * @memberof MRecordRTC - * @example - * recorder.writeToDisk(); - */ - this.writeToDisk = function() { - RecordRTC.writeToDisk({ - audio: this.audioRecorder, - video: this.videoRecorder, - gif: this.gifRecorder - }); - }; - - /** - * This method can be used to invoke a save-as dialog for all recorded blobs. - * @param {object} args - {audio: 'audio-name', video: 'video-name', gif: 'gif-name'} - * @method - * @memberof MRecordRTC - * @example - * recorder.save({ - * audio: 'audio-file-name', - * video: 'video-file-name', - * gif : 'gif-file-name' - * }); - */ - this.save = function(args) { - args = args || { - audio: true, - video: true, - gif: true - }; - - if (!!args.audio && this.audioRecorder) { - this.audioRecorder.save(typeof args.audio === 'string' ? args.audio : ''); - } - - if (!!args.video && this.videoRecorder) { - this.videoRecorder.save(typeof args.video === 'string' ? args.video : ''); - } - if (!!args.gif && this.gifRecorder) { - this.gifRecorder.save(typeof args.gif === 'string' ? args.gif : ''); - } - }; -} - -/** - * This method can be used to get all recorded blobs from IndexedDB storage. - * @param {string} type - 'all' or 'audio' or 'video' or 'gif' - * @param {function} callback - Callback function to get all stored blobs. - * @method - * @memberof MRecordRTC - * @example - * MRecordRTC.getFromDisk('all', function(dataURL, type){ - * if(type === 'audio') { } - * if(type === 'video') { } - * if(type === 'gif') { } - * }); - */ -MRecordRTC.getFromDisk = RecordRTC.getFromDisk; - -/** - * This method can be used to store recorded blobs into IndexedDB storage. - * @param {object} options - {audio: Blob, video: Blob, gif: Blob} - * @method - * @memberof MRecordRTC - * @example - * MRecordRTC.writeToDisk({ - * audio: audioBlob, - * video: videoBlob, - * gif : gifBlob - * }); - */ -MRecordRTC.writeToDisk = RecordRTC.writeToDisk; - -if (typeof RecordRTC !== 'undefined') { - RecordRTC.MRecordRTC = MRecordRTC; -} - -var browserFakeUserAgent = 'Fake/5.0 (FakeOS) AppleWebKit/123 (KHTML, like Gecko) Fake/12.3.4567.89 Fake/123.45'; - -(function(that) { - if (!that) { - return; - } - - if (typeof window !== 'undefined') { - return; - } - - if (typeof global === 'undefined') { - return; - } - - global.navigator = { - userAgent: browserFakeUserAgent, - getUserMedia: function() {} - }; - - if (!global.console) { - global.console = {}; - } - - if (typeof global.console.log === 'undefined' || typeof global.console.error === 'undefined') { - global.console.error = global.console.log = global.console.log || function() { - console.log(arguments); - }; - } - - if (typeof document === 'undefined') { - /*global document:true */ - that.document = { - documentElement: { - appendChild: function() { - return ''; - } - } - }; - - document.createElement = document.captureStream = document.mozCaptureStream = function() { - var obj = { - getContext: function() { - return obj; - }, - play: function() {}, - pause: function() {}, - drawImage: function() {}, - toDataURL: function() { - return ''; - }, - style: {} - }; - return obj; - }; - - that.HTMLVideoElement = function() {}; - } - - if (typeof location === 'undefined') { - /*global location:true */ - that.location = { - protocol: 'file:', - href: '', - hash: '' - }; - } - - if (typeof screen === 'undefined') { - /*global screen:true */ - that.screen = { - width: 0, - height: 0 - }; - } - - if (typeof URL === 'undefined') { - /*global screen:true */ - that.URL = { - createObjectURL: function() { - return ''; - }, - revokeObjectURL: function() { - return ''; - } - }; - } - - /*global window:true */ - that.window = global; -})(typeof global !== 'undefined' ? global : null); - -// _____________________________ -// Cross-Browser-Declarations.js - -// animation-frame used in WebM recording - -/*jshint -W079 */ -var requestAnimationFrame = window.requestAnimationFrame; -if (typeof requestAnimationFrame === 'undefined') { - if (typeof webkitRequestAnimationFrame !== 'undefined') { - /*global requestAnimationFrame:true */ - requestAnimationFrame = webkitRequestAnimationFrame; - } else if (typeof mozRequestAnimationFrame !== 'undefined') { - /*global requestAnimationFrame:true */ - requestAnimationFrame = mozRequestAnimationFrame; - } else if (typeof msRequestAnimationFrame !== 'undefined') { - /*global requestAnimationFrame:true */ - requestAnimationFrame = msRequestAnimationFrame; - } else if (typeof requestAnimationFrame === 'undefined') { - // via: https://gist.github.com/paulirish/1579671 - var lastTime = 0; - - /*global requestAnimationFrame:true */ - requestAnimationFrame = function(callback, element) { - var currTime = new Date().getTime(); - var timeToCall = Math.max(0, 16 - (currTime - lastTime)); - var id = setTimeout(function() { - callback(currTime + timeToCall); - }, timeToCall); - lastTime = currTime + timeToCall; - return id; - }; - } -} - -/*jshint -W079 */ -var cancelAnimationFrame = window.cancelAnimationFrame; -if (typeof cancelAnimationFrame === 'undefined') { - if (typeof webkitCancelAnimationFrame !== 'undefined') { - /*global cancelAnimationFrame:true */ - cancelAnimationFrame = webkitCancelAnimationFrame; - } else if (typeof mozCancelAnimationFrame !== 'undefined') { - /*global cancelAnimationFrame:true */ - cancelAnimationFrame = mozCancelAnimationFrame; - } else if (typeof msCancelAnimationFrame !== 'undefined') { - /*global cancelAnimationFrame:true */ - cancelAnimationFrame = msCancelAnimationFrame; - } else if (typeof cancelAnimationFrame === 'undefined') { - /*global cancelAnimationFrame:true */ - cancelAnimationFrame = function(id) { - clearTimeout(id); - }; - } -} - -// WebAudio API representer -var AudioContext = window.AudioContext; - -if (typeof AudioContext === 'undefined') { - if (typeof webkitAudioContext !== 'undefined') { - /*global AudioContext:true */ - AudioContext = webkitAudioContext; - } - - if (typeof mozAudioContext !== 'undefined') { - /*global AudioContext:true */ - AudioContext = mozAudioContext; - } -} - -/*jshint -W079 */ -var URL = window.URL; - -if (typeof URL === 'undefined' && typeof webkitURL !== 'undefined') { - /*global URL:true */ - URL = webkitURL; -} - -if (typeof navigator !== 'undefined' && typeof navigator.getUserMedia === 'undefined') { // maybe window.navigator? - if (typeof navigator.webkitGetUserMedia !== 'undefined') { - navigator.getUserMedia = navigator.webkitGetUserMedia; - } - - if (typeof navigator.mozGetUserMedia !== 'undefined') { - navigator.getUserMedia = navigator.mozGetUserMedia; - } -} - -var isEdge = navigator.userAgent.indexOf('Edge') !== -1 && (!!navigator.msSaveBlob || !!navigator.msSaveOrOpenBlob); -var isOpera = !!window.opera || navigator.userAgent.indexOf('OPR/') !== -1; -var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && ('netscape' in window) && / rv:/.test(navigator.userAgent); -var isChrome = (!isOpera && !isEdge && !!navigator.webkitGetUserMedia) || isElectron() || navigator.userAgent.toLowerCase().indexOf('chrome/') !== -1; - -var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); - -if (isSafari && !isChrome && navigator.userAgent.indexOf('CriOS') !== -1) { - isSafari = false; - isChrome = true; -} - -var MediaStream = window.MediaStream; - -if (typeof MediaStream === 'undefined' && typeof webkitMediaStream !== 'undefined') { - MediaStream = webkitMediaStream; -} - -/*global MediaStream:true */ -if (typeof MediaStream !== 'undefined') { - // override "stop" method for all browsers - if (typeof MediaStream.prototype.stop === 'undefined') { - MediaStream.prototype.stop = function() { - this.getTracks().forEach(function(track) { - track.stop(); - }); - }; - } -} - -// below function via: http://goo.gl/B3ae8c -/** - * Return human-readable file size. - * @param {number} bytes - Pass bytes and get formatted string. - * @returns {string} - formatted string - * @example - * bytesToSize(1024*1024*5) === '5 GB' - * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} - */ -function bytesToSize(bytes) { - var k = 1000; - var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; - if (bytes === 0) { - return '0 Bytes'; - } - var i = parseInt(Math.floor(Math.log(bytes) / Math.log(k)), 10); - return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i]; -} - -/** - * @param {Blob} file - File or Blob object. This parameter is required. - * @param {string} fileName - Optional file name e.g. "Recorded-Video.webm" - * @example - * invokeSaveAsDialog(blob or file, [optional] fileName); - * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} - */ -function invokeSaveAsDialog(file, fileName) { - if (!file) { - throw 'Blob object is required.'; - } - - if (!file.type) { - try { - file.type = 'video/webm'; - } catch (e) {} - } - - var fileExtension = (file.type || 'video/webm').split('/')[1]; - - if (fileName && fileName.indexOf('.') !== -1) { - var splitted = fileName.split('.'); - fileName = splitted[0]; - fileExtension = splitted[1]; - } - - var fileFullName = (fileName || (Math.round(Math.random() * 9999999999) + 888888888)) + '.' + fileExtension; - - if (typeof navigator.msSaveOrOpenBlob !== 'undefined') { - return navigator.msSaveOrOpenBlob(file, fileFullName); - } else if (typeof navigator.msSaveBlob !== 'undefined') { - return navigator.msSaveBlob(file, fileFullName); - } - - var hyperlink = document.createElement('a'); - hyperlink.href = URL.createObjectURL(file); - hyperlink.download = fileFullName; - - hyperlink.style = 'display:none;opacity:0;color:transparent;'; - (document.body || document.documentElement).appendChild(hyperlink); - - if (typeof hyperlink.click === 'function') { - hyperlink.click(); - } else { - hyperlink.target = '_blank'; - hyperlink.dispatchEvent(new MouseEvent('click', { - view: window, - bubbles: true, - cancelable: true - })); - } - - URL.revokeObjectURL(hyperlink.href); -} - -/** - * from: https://github.com/cheton/is-electron/blob/master/index.js - **/ -function isElectron() { - // Renderer process - if (typeof window !== 'undefined' && typeof window.process === 'object' && window.process.type === 'renderer') { - return true; - } - - // Main process - if (typeof process !== 'undefined' && typeof process.versions === 'object' && !!process.versions.electron) { - return true; - } - - // Detect the user agent when the `nodeIntegration` option is set to true - if (typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent.indexOf('Electron') >= 0) { - return true; - } - - return false; -} - -function getTracks(stream, kind) { - if (!stream || !stream.getTracks) { - return []; - } - - return stream.getTracks().filter(function(t) { - return t.kind === (kind || 'audio'); - }); -} - -function setSrcObject(stream, element) { - if ('srcObject' in element) { - element.srcObject = stream; - } else if ('mozSrcObject' in element) { - element.mozSrcObject = stream; - } else { - element.srcObject = stream; - } -} - -/** - * @param {Blob} file - File or Blob object. - * @param {function} callback - Callback function. - * @example - * getSeekableBlob(blob or file, callback); - * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} - */ -function getSeekableBlob(inputBlob, callback) { - // EBML.js copyrights goes to: https://github.com/legokichi/ts-ebml - if (typeof EBML === 'undefined') { - throw new Error('Please link: https://www.webrtc-experiment.com/EBML.js'); - } - - var reader = new EBML.Reader(); - var decoder = new EBML.Decoder(); - var tools = EBML.tools; - - var fileReader = new FileReader(); - fileReader.onload = function(e) { - var ebmlElms = decoder.decode(this.result); - ebmlElms.forEach(function(element) { - reader.read(element); - }); - reader.stop(); - var refinedMetadataBuf = tools.makeMetadataSeekable(reader.metadatas, reader.duration, reader.cues); - var body = this.result.slice(reader.metadataSize); - var newBlob = new Blob([refinedMetadataBuf, body], { - type: 'video/webm' - }); - - callback(newBlob); - }; - fileReader.readAsArrayBuffer(inputBlob); -} - -if (typeof RecordRTC !== 'undefined') { - RecordRTC.invokeSaveAsDialog = invokeSaveAsDialog; - RecordRTC.getTracks = getTracks; - RecordRTC.getSeekableBlob = getSeekableBlob; - RecordRTC.bytesToSize = bytesToSize; - RecordRTC.isElectron = isElectron; -} - -// __________ (used to handle stuff like http://goo.gl/xmE5eg) issue #129 -// Storage.js - -/** - * Storage is a standalone object used by {@link RecordRTC} to store reusable objects e.g. "new AudioContext". - * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} - * @author {@link https://MuazKhan.com|Muaz Khan} - * @example - * Storage.AudioContext === webkitAudioContext - * @property {webkitAudioContext} AudioContext - Keeps a reference to AudioContext object. - * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} - */ - -var Storage = {}; - -if (typeof AudioContext !== 'undefined') { - Storage.AudioContext = AudioContext; -} else if (typeof webkitAudioContext !== 'undefined') { - Storage.AudioContext = webkitAudioContext; -} - -if (typeof RecordRTC !== 'undefined') { - RecordRTC.Storage = Storage; -} - -function isMediaRecorderCompatible() { - if (isFirefox || isSafari || isEdge) { - return true; - } - - var nVer = navigator.appVersion; - var nAgt = navigator.userAgent; - var fullVersion = '' + parseFloat(navigator.appVersion); - var majorVersion = parseInt(navigator.appVersion, 10); - var nameOffset, verOffset, ix; - - if (isChrome || isOpera) { - verOffset = nAgt.indexOf('Chrome'); - fullVersion = nAgt.substring(verOffset + 7); - } - - // trim the fullVersion string at semicolon/space if present - if ((ix = fullVersion.indexOf(';')) !== -1) { - fullVersion = fullVersion.substring(0, ix); - } - - if ((ix = fullVersion.indexOf(' ')) !== -1) { - fullVersion = fullVersion.substring(0, ix); - } - - majorVersion = parseInt('' + fullVersion, 10); - - if (isNaN(majorVersion)) { - fullVersion = '' + parseFloat(navigator.appVersion); - majorVersion = parseInt(navigator.appVersion, 10); - } - - return majorVersion >= 49; -} - -// ______________________ -// MediaStreamRecorder.js - -/** - * MediaStreamRecorder is an abstraction layer for {@link https://w3c.github.io/mediacapture-record/MediaRecorder.html|MediaRecorder API}. It is used by {@link RecordRTC} to record MediaStream(s) in both Chrome and Firefox. - * @summary Runs top over {@link https://w3c.github.io/mediacapture-record/MediaRecorder.html|MediaRecorder API}. - * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} - * @author {@link https://github.com/muaz-khan|Muaz Khan} - * @typedef MediaStreamRecorder - * @class - * @example - * var config = { - * mimeType: 'video/webm', // vp8, vp9, h264, mkv, opus/vorbis - * audioBitsPerSecond : 256 * 8 * 1024, - * videoBitsPerSecond : 256 * 8 * 1024, - * bitsPerSecond: 256 * 8 * 1024, // if this is provided, skip above two - * checkForInactiveTracks: true, - * timeSlice: 1000, // concatenate intervals based blobs - * ondataavailable: function() {} // get intervals based blobs - * } - * var recorder = new MediaStreamRecorder(mediaStream, config); - * recorder.record(); - * recorder.stop(function(blob) { - * video.src = URL.createObjectURL(blob); - * - * // or - * var blob = recorder.blob; - * }); - * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} - * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API. - * @param {object} config - {disableLogs:true, initCallback: function, mimeType: "video/webm", timeSlice: 1000} - * @throws Will throw an error if first argument "MediaStream" is missing. Also throws error if "MediaRecorder API" are not supported by the browser. - */ - -function MediaStreamRecorder(mediaStream, config) { - var self = this; - - if (typeof mediaStream === 'undefined') { - throw 'First argument "MediaStream" is required.'; - } - - if (typeof MediaRecorder === 'undefined') { - throw 'Your browser does not support the Media Recorder API. Please try other modules e.g. WhammyRecorder or StereoAudioRecorder.'; - } - - config = config || { - // bitsPerSecond: 256 * 8 * 1024, - mimeType: 'video/webm' - }; - - if (config.type === 'audio') { - if (getTracks(mediaStream, 'video').length && getTracks(mediaStream, 'audio').length) { - var stream; - if (!!navigator.mozGetUserMedia) { - stream = new MediaStream(); - stream.addTrack(getTracks(mediaStream, 'audio')[0]); - } else { - // webkitMediaStream - stream = new MediaStream(getTracks(mediaStream, 'audio')); - } - mediaStream = stream; - } - - if (!config.mimeType || config.mimeType.toString().toLowerCase().indexOf('audio') === -1) { - config.mimeType = isChrome ? 'audio/webm' : 'audio/ogg'; - } - - if (config.mimeType && config.mimeType.toString().toLowerCase() !== 'audio/ogg' && !!navigator.mozGetUserMedia) { - // forcing better codecs on Firefox (via #166) - config.mimeType = 'audio/ogg'; - } - } - - var arrayOfBlobs = []; - - /** - * This method returns array of blobs. Use only with "timeSlice". Its useful to preview recording anytime, without using the "stop" method. - * @method - * @memberof MediaStreamRecorder - * @example - * var arrayOfBlobs = recorder.getArrayOfBlobs(); - * @returns {Array} Returns array of recorded blobs. - */ - this.getArrayOfBlobs = function() { - return arrayOfBlobs; - }; - - /** - * This method records MediaStream. - * @method - * @memberof MediaStreamRecorder - * @example - * recorder.record(); - */ - this.record = function() { - // set defaults - self.blob = null; - self.clearRecordedData(); - self.timestamps = []; - allStates = []; - arrayOfBlobs = []; - - var recorderHints = config; - - if (!config.disableLogs) { - console.log('Passing following config over MediaRecorder API.', recorderHints); - } - - if (mediaRecorder) { - // mandatory to make sure Firefox doesn't fails to record streams 3-4 times without reloading the page. - mediaRecorder = null; - } - - if (isChrome && !isMediaRecorderCompatible()) { - // to support video-only recording on stable - recorderHints = 'video/vp8'; - } - - if (typeof MediaRecorder.isTypeSupported === 'function' && recorderHints.mimeType) { - if (!MediaRecorder.isTypeSupported(recorderHints.mimeType)) { - if (!config.disableLogs) { - console.warn('MediaRecorder API seems unable to record mimeType:', recorderHints.mimeType); - } - - recorderHints.mimeType = config.type === 'audio' ? 'audio/webm' : 'video/webm'; - } - } - - // using MediaRecorder API here - try { - mediaRecorder = new MediaRecorder(mediaStream, recorderHints); - - // reset - config.mimeType = recorderHints.mimeType; - } catch (e) { - // chrome-based fallback - mediaRecorder = new MediaRecorder(mediaStream); - } - - // old hack? - if (recorderHints.mimeType && !MediaRecorder.isTypeSupported && 'canRecordMimeType' in mediaRecorder && mediaRecorder.canRecordMimeType(recorderHints.mimeType) === false) { - if (!config.disableLogs) { - console.warn('MediaRecorder API seems unable to record mimeType:', recorderHints.mimeType); - } - } - - // Dispatching OnDataAvailable Handler - mediaRecorder.ondataavailable = function(e) { - if (e.data) { - allStates.push('ondataavailable: ' + bytesToSize(e.data.size)); - } - - if (typeof config.timeSlice === 'number') { - if (e.data && e.data.size && e.data.size > 100) { - arrayOfBlobs.push(e.data); - updateTimeStamp(); - - if (typeof config.ondataavailable === 'function') { - // intervals based blobs - var blob = config.getNativeBlob ? e.data : new Blob([e.data], { - type: getMimeType(recorderHints) - }); - config.ondataavailable(blob); - } - } - return; - } - - if (!e.data || !e.data.size || e.data.size < 100 || self.blob) { - // make sure that stopRecording always getting fired - // even if there is invalid data - if (self.recordingCallback) { - self.recordingCallback(new Blob([], { - type: getMimeType(recorderHints) - })); - self.recordingCallback = null; - } - return; - } - - self.blob = config.getNativeBlob ? e.data : new Blob([e.data], { - type: getMimeType(recorderHints) - }); - - if (self.recordingCallback) { - self.recordingCallback(self.blob); - self.recordingCallback = null; - } - }; - - mediaRecorder.onstart = function() { - allStates.push('started'); - }; - - mediaRecorder.onpause = function() { - allStates.push('paused'); - }; - - mediaRecorder.onresume = function() { - allStates.push('resumed'); - }; - - mediaRecorder.onstop = function() { - allStates.push('stopped'); - }; - - mediaRecorder.onerror = function(error) { - if (!error) { - return; - } - - if (!error.name) { - error.name = 'UnknownError'; - } - - allStates.push('error: ' + error); - - if (!config.disableLogs) { - // via: https://w3c.github.io/mediacapture-record/MediaRecorder.html#exception-summary - if (error.name.toString().toLowerCase().indexOf('invalidstate') !== -1) { - console.error('The MediaRecorder is not in a state in which the proposed operation is allowed to be executed.', error); - } else if (error.name.toString().toLowerCase().indexOf('notsupported') !== -1) { - console.error('MIME type (', recorderHints.mimeType, ') is not supported.', error); - } else if (error.name.toString().toLowerCase().indexOf('security') !== -1) { - console.error('MediaRecorder security error', error); - } - - // older code below - else if (error.name === 'OutOfMemory') { - console.error('The UA has exhaused the available memory. User agents SHOULD provide as much additional information as possible in the message attribute.', error); - } else if (error.name === 'IllegalStreamModification') { - console.error('A modification to the stream has occurred that makes it impossible to continue recording. An example would be the addition of a Track while recording is occurring. User agents SHOULD provide as much additional information as possible in the message attribute.', error); - } else if (error.name === 'OtherRecordingError') { - console.error('Used for an fatal error other than those listed above. User agents SHOULD provide as much additional information as possible in the message attribute.', error); - } else if (error.name === 'GenericError') { - console.error('The UA cannot provide the codec or recording option that has been requested.', error); - } else { - console.error('MediaRecorder Error', error); - } - } - - (function(looper) { - if (!self.manuallyStopped && mediaRecorder && mediaRecorder.state === 'inactive') { - delete config.timeslice; - - // 10 minutes, enough? - mediaRecorder.start(10 * 60 * 1000); - return; - } - - setTimeout(looper, 1000); - })(); - - if (mediaRecorder.state !== 'inactive' && mediaRecorder.state !== 'stopped') { - mediaRecorder.stop(); - } - }; - - if (typeof config.timeSlice === 'number') { - updateTimeStamp(); - mediaRecorder.start(config.timeSlice); - } else { - // default is 60 minutes; enough? - // use config => {timeSlice: 1000} otherwise - - mediaRecorder.start(3.6e+6); - } - - if (config.initCallback) { - config.initCallback(); // old code - } - }; - - /** - * @property {Array} timestamps - Array of time stamps - * @memberof MediaStreamRecorder - * @example - * console.log(recorder.timestamps); - */ - this.timestamps = []; - - function updateTimeStamp() { - self.timestamps.push(new Date().getTime()); - - if (typeof config.onTimeStamp === 'function') { - config.onTimeStamp(self.timestamps[self.timestamps.length - 1], self.timestamps); - } - } - - function getMimeType(secondObject) { - if (mediaRecorder && mediaRecorder.mimeType) { - return mediaRecorder.mimeType; - } - - return secondObject.mimeType || 'video/webm'; - } - - /** - * This method stops recording MediaStream. - * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee. - * @method - * @memberof MediaStreamRecorder - * @example - * recorder.stop(function(blob) { - * video.src = URL.createObjectURL(blob); - * }); - */ - this.stop = function(callback) { - callback = callback || function() {}; - - self.manuallyStopped = true; // used inside the mediaRecorder.onerror - - if (!mediaRecorder) { - return; - } - - this.recordingCallback = callback; - - if (mediaRecorder.state === 'recording') { - mediaRecorder.stop(); - } - - if (typeof config.timeSlice === 'number') { - setTimeout(function() { - self.blob = new Blob(arrayOfBlobs, { - type: getMimeType(config) - }); - - self.recordingCallback(self.blob); - }, 100); - } - }; - - /** - * This method pauses the recording process. - * @method - * @memberof MediaStreamRecorder - * @example - * recorder.pause(); - */ - this.pause = function() { - if (!mediaRecorder) { - return; - } - - if (mediaRecorder.state === 'recording') { - mediaRecorder.pause(); - } - }; - - /** - * This method resumes the recording process. - * @method - * @memberof MediaStreamRecorder - * @example - * recorder.resume(); - */ - this.resume = function() { - if (!mediaRecorder) { - return; - } - - if (mediaRecorder.state === 'paused') { - mediaRecorder.resume(); - } - }; - - /** - * This method resets currently recorded data. - * @method - * @memberof MediaStreamRecorder - * @example - * recorder.clearRecordedData(); - */ - this.clearRecordedData = function() { - if (mediaRecorder && mediaRecorder.state === 'recording') { - self.stop(clearRecordedDataCB); - } - - clearRecordedDataCB(); - }; - - function clearRecordedDataCB() { - arrayOfBlobs = []; - mediaRecorder = null; - self.timestamps = []; - } - - // Reference to "MediaRecorder" object - var mediaRecorder; - - /** - * Access to native MediaRecorder API - * @method - * @memberof MediaStreamRecorder - * @instance - * @example - * var internal = recorder.getInternalRecorder(); - * internal.ondataavailable = function() {}; // override - * internal.stream, internal.onpause, internal.onstop, etc. - * @returns {Object} Returns internal recording object. - */ - this.getInternalRecorder = function() { - return mediaRecorder; - }; - - function isMediaStreamActive() { - if ('active' in mediaStream) { - if (!mediaStream.active) { - return false; - } - } else if ('ended' in mediaStream) { // old hack - if (mediaStream.ended) { - return false; - } - } - return true; - } - - /** - * @property {Blob} blob - Recorded data as "Blob" object. - * @memberof MediaStreamRecorder - * @example - * recorder.stop(function() { - * var blob = recorder.blob; - * }); - */ - this.blob = null; - - - /** - * Get MediaRecorder readonly state. - * @method - * @memberof MediaStreamRecorder - * @example - * var state = recorder.getState(); - * @returns {String} Returns recording state. - */ - this.getState = function() { - if (!mediaRecorder) { - return 'inactive'; - } - - return mediaRecorder.state || 'inactive'; - }; - - // list of all recording states - var allStates = []; - - /** - * Get MediaRecorder all recording states. - * @method - * @memberof MediaStreamRecorder - * @example - * var state = recorder.getAllStates(); - * @returns {Array} Returns all recording states - */ - this.getAllStates = function() { - return allStates; - }; - - // if any Track within the MediaStream is muted or not enabled at any time, - // the browser will only record black frames - // or silence since that is the content produced by the Track - // so we need to stopRecording as soon as any single track ends. - if (typeof config.checkForInactiveTracks === 'undefined') { - config.checkForInactiveTracks = false; // disable to minimize CPU usage - } - - var self = this; - - // this method checks if media stream is stopped - // or if any track is ended. - (function looper() { - if (!mediaRecorder || config.checkForInactiveTracks === false) { - return; - } - - if (isMediaStreamActive() === false) { - if (!config.disableLogs) { - console.log('MediaStream seems stopped.'); - } - self.stop(); - return; - } - - setTimeout(looper, 1000); // check every second - })(); - - // for debugging - this.name = 'MediaStreamRecorder'; - this.toString = function() { - return this.name; - }; -} - -if (typeof RecordRTC !== 'undefined') { - RecordRTC.MediaStreamRecorder = MediaStreamRecorder; -} - -// source code from: http://typedarray.org/wp-content/projects/WebAudioRecorder/script.js -// https://github.com/mattdiamond/Recorderjs#license-mit -// ______________________ -// StereoAudioRecorder.js - -/** - * StereoAudioRecorder is a standalone class used by {@link RecordRTC} to bring "stereo" audio-recording in chrome. - * @summary JavaScript standalone object for stereo audio recording. - * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} - * @author {@link https://MuazKhan.com|Muaz Khan} - * @typedef StereoAudioRecorder - * @class - * @example - * var recorder = new StereoAudioRecorder(MediaStream, { - * sampleRate: 44100, - * bufferSize: 4096 - * }); - * recorder.record(); - * recorder.stop(function(blob) { - * video.src = URL.createObjectURL(blob); - * }); - * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} - * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API. - * @param {object} config - {sampleRate: 44100, bufferSize: 4096, numberOfAudioChannels: 1, etc.} - */ - -function StereoAudioRecorder(mediaStream, config) { - if (!getTracks(mediaStream, 'audio').length) { - throw 'Your stream has no audio tracks.'; - } - - config = config || {}; - - var self = this; - - // variables - var leftchannel = []; - var rightchannel = []; - var recording = false; - var recordingLength = 0; - var jsAudioNode; - - var numberOfAudioChannels = 2; - - /** - * Set sample rates such as 8K or 16K. Reference: http://stackoverflow.com/a/28977136/552182 - * @property {number} desiredSampRate - Desired Bits per sample * 1000 - * @memberof StereoAudioRecorder - * @instance - * @example - * var recorder = StereoAudioRecorder(mediaStream, { - * desiredSampRate: 16 * 1000 // bits-per-sample * 1000 - * }); - */ - var desiredSampRate = config.desiredSampRate; - - // backward compatibility - if (config.leftChannel === true) { - numberOfAudioChannels = 1; - } - - if (config.numberOfAudioChannels === 1) { - numberOfAudioChannels = 1; - } - - if (!numberOfAudioChannels || numberOfAudioChannels < 1) { - numberOfAudioChannels = 2; - } - - if (!config.disableLogs) { - console.log('StereoAudioRecorder is set to record number of channels: ' + numberOfAudioChannels); - } - - // if any Track within the MediaStream is muted or not enabled at any time, - // the browser will only record black frames - // or silence since that is the content produced by the Track - // so we need to stopRecording as soon as any single track ends. - if (typeof config.checkForInactiveTracks === 'undefined') { - config.checkForInactiveTracks = true; - } - - function isMediaStreamActive() { - if (config.checkForInactiveTracks === false) { - // always return "true" - return true; - } - - if ('active' in mediaStream) { - if (!mediaStream.active) { - return false; - } - } else if ('ended' in mediaStream) { // old hack - if (mediaStream.ended) { - return false; - } - } - return true; - } - - /** - * This method records MediaStream. - * @method - * @memberof StereoAudioRecorder - * @example - * recorder.record(); - */ - this.record = function() { - if (isMediaStreamActive() === false) { - throw 'Please make sure MediaStream is active.'; - } - - resetVariables(); - - isAudioProcessStarted = isPaused = false; - recording = true; - - if (typeof config.timeSlice !== 'undefined') { - looper(); - } - }; - - function mergeLeftRightBuffers(config, callback) { - function mergeAudioBuffers(config, cb) { - var numberOfAudioChannels = config.numberOfAudioChannels; - - // todo: "slice(0)" --- is it causes loop? Should be removed? - var leftBuffers = config.leftBuffers.slice(0); - var rightBuffers = config.rightBuffers.slice(0); - var sampleRate = config.sampleRate; - var internalInterleavedLength = config.internalInterleavedLength; - var desiredSampRate = config.desiredSampRate; - - if (numberOfAudioChannels === 2) { - leftBuffers = mergeBuffers(leftBuffers, internalInterleavedLength); - rightBuffers = mergeBuffers(rightBuffers, internalInterleavedLength); - - if (desiredSampRate) { - leftBuffers = interpolateArray(leftBuffers, desiredSampRate, sampleRate); - rightBuffers = interpolateArray(rightBuffers, desiredSampRate, sampleRate); - } - } - - if (numberOfAudioChannels === 1) { - leftBuffers = mergeBuffers(leftBuffers, internalInterleavedLength); - - if (desiredSampRate) { - leftBuffers = interpolateArray(leftBuffers, desiredSampRate, sampleRate); - } - } - - // set sample rate as desired sample rate - if (desiredSampRate) { - sampleRate = desiredSampRate; - } - - // for changing the sampling rate, reference: - // http://stackoverflow.com/a/28977136/552182 - function interpolateArray(data, newSampleRate, oldSampleRate) { - var fitCount = Math.round(data.length * (newSampleRate / oldSampleRate)); - var newData = []; - var springFactor = Number((data.length - 1) / (fitCount - 1)); - newData[0] = data[0]; - for (var i = 1; i < fitCount - 1; i++) { - var tmp = i * springFactor; - var before = Number(Math.floor(tmp)).toFixed(); - var after = Number(Math.ceil(tmp)).toFixed(); - var atPoint = tmp - before; - newData[i] = linearInterpolate(data[before], data[after], atPoint); - } - newData[fitCount - 1] = data[data.length - 1]; - return newData; - } - - function linearInterpolate(before, after, atPoint) { - return before + (after - before) * atPoint; - } - - function mergeBuffers(channelBuffer, rLength) { - var result = new Float64Array(rLength); - var offset = 0; - var lng = channelBuffer.length; - - for (var i = 0; i < lng; i++) { - var buffer = channelBuffer[i]; - result.set(buffer, offset); - offset += buffer.length; - } - - return result; - } - - function interleave(leftChannel, rightChannel) { - var length = leftChannel.length + rightChannel.length; - - var result = new Float64Array(length); - - var inputIndex = 0; - - for (var index = 0; index < length;) { - result[index++] = leftChannel[inputIndex]; - result[index++] = rightChannel[inputIndex]; - inputIndex++; - } - return result; - } - - function writeUTFBytes(view, offset, string) { - var lng = string.length; - for (var i = 0; i < lng; i++) { - view.setUint8(offset + i, string.charCodeAt(i)); - } - } - - // interleave both channels together - var interleaved; - - if (numberOfAudioChannels === 2) { - interleaved = interleave(leftBuffers, rightBuffers); - } - - if (numberOfAudioChannels === 1) { - interleaved = leftBuffers; - } - - var interleavedLength = interleaved.length; - - // create wav file - var resultingBufferLength = 44 + interleavedLength * 2; - - var buffer = new ArrayBuffer(resultingBufferLength); - - var view = new DataView(buffer); - - // RIFF chunk descriptor/identifier - writeUTFBytes(view, 0, 'RIFF'); - - // RIFF chunk length - // changed "44" to "36" via #401 - view.setUint32(4, 36 + interleavedLength * 2, true); - - // RIFF type - writeUTFBytes(view, 8, 'WAVE'); - - // format chunk identifier - // FMT sub-chunk - writeUTFBytes(view, 12, 'fmt '); - - // format chunk length - view.setUint32(16, 16, true); - - // sample format (raw) - view.setUint16(20, 1, true); - - // stereo (2 channels) - view.setUint16(22, numberOfAudioChannels, true); - - // sample rate - view.setUint32(24, sampleRate, true); - - // byte rate (sample rate * block align) - view.setUint32(28, sampleRate * 2, true); - - // block align (channel count * bytes per sample) - view.setUint16(32, numberOfAudioChannels * 2, true); - - // bits per sample - view.setUint16(34, 16, true); - - // data sub-chunk - // data chunk identifier - writeUTFBytes(view, 36, 'data'); - - // data chunk length - view.setUint32(40, interleavedLength * 2, true); - - // write the PCM samples - var lng = interleavedLength; - var index = 44; - var volume = 1; - for (var i = 0; i < lng; i++) { - view.setInt16(index, interleaved[i] * (0x7FFF * volume), true); - index += 2; - } - - if (cb) { - return cb({ - buffer: buffer, - view: view - }); - } - - postMessage({ - buffer: buffer, - view: view - }); - } - - if (config.noWorker) { - mergeAudioBuffers(config, function(data) { - callback(data.buffer, data.view); - }); - return; - } - - - var webWorker = processInWebWorker(mergeAudioBuffers); - - webWorker.onmessage = function(event) { - callback(event.data.buffer, event.data.view); - - // release memory - URL.revokeObjectURL(webWorker.workerURL); - - // kill webworker (or Chrome will kill your page after ~25 calls) - webWorker.terminate(); - }; - - webWorker.postMessage(config); - } - - function processInWebWorker(_function) { - var workerURL = URL.createObjectURL(new Blob([_function.toString(), - ';this.onmessage = function (eee) {' + _function.name + '(eee.data);}' - ], { - type: 'application/javascript' - })); - - var worker = new Worker(workerURL); - worker.workerURL = workerURL; - return worker; - } - - /** - * This method stops recording MediaStream. - * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee. - * @method - * @memberof StereoAudioRecorder - * @example - * recorder.stop(function(blob) { - * video.src = URL.createObjectURL(blob); - * }); - */ - this.stop = function(callback) { - callback = callback || function() {}; - - // stop recording - recording = false; - - mergeLeftRightBuffers({ - desiredSampRate: desiredSampRate, - sampleRate: sampleRate, - numberOfAudioChannels: numberOfAudioChannels, - internalInterleavedLength: recordingLength, - leftBuffers: leftchannel, - rightBuffers: numberOfAudioChannels === 1 ? [] : rightchannel, - noWorker: config.noWorker - }, function(buffer, view) { - /** - * @property {Blob} blob - The recorded blob object. - * @memberof StereoAudioRecorder - * @example - * recorder.stop(function(){ - * var blob = recorder.blob; - * }); - */ - self.blob = new Blob([view], { - type: 'audio/wav' - }); - - /** - * @property {ArrayBuffer} buffer - The recorded buffer object. - * @memberof StereoAudioRecorder - * @example - * recorder.stop(function(){ - * var buffer = recorder.buffer; - * }); - */ - self.buffer = new ArrayBuffer(view.buffer.byteLength); - - /** - * @property {DataView} view - The recorded data-view object. - * @memberof StereoAudioRecorder - * @example - * recorder.stop(function(){ - * var view = recorder.view; - * }); - */ - self.view = view; - - self.sampleRate = desiredSampRate || sampleRate; - self.bufferSize = bufferSize; - - // recorded audio length - self.length = recordingLength; - - isAudioProcessStarted = false; - - if (callback) { - callback(self.blob); - } - }); - }; - - if (typeof RecordRTC.Storage === 'undefined') { - RecordRTC.Storage = { - AudioContextConstructor: null, - AudioContext: window.AudioContext || window.webkitAudioContext - }; - } - - if (!RecordRTC.Storage.AudioContextConstructor || RecordRTC.Storage.AudioContextConstructor.state === 'closed') { - RecordRTC.Storage.AudioContextConstructor = new RecordRTC.Storage.AudioContext(); - } - - var context = RecordRTC.Storage.AudioContextConstructor; - - // creates an audio node from the microphone incoming stream - var audioInput = context.createMediaStreamSource(mediaStream); - - var legalBufferValues = [0, 256, 512, 1024, 2048, 4096, 8192, 16384]; - - /** - * From the spec: This value controls how frequently the audioprocess event is - * dispatched and how many sample-frames need to be processed each call. - * Lower values for buffer size will result in a lower (better) latency. - * Higher values will be necessary to avoid audio breakup and glitches - * The size of the buffer (in sample-frames) which needs to - * be processed each time onprocessaudio is called. - * Legal values are (256, 512, 1024, 2048, 4096, 8192, 16384). - * @property {number} bufferSize - Buffer-size for how frequently the audioprocess event is dispatched. - * @memberof StereoAudioRecorder - * @example - * recorder = new StereoAudioRecorder(mediaStream, { - * bufferSize: 4096 - * }); - */ - - // "0" means, let chrome decide the most accurate buffer-size for current platform. - var bufferSize = typeof config.bufferSize === 'undefined' ? 4096 : config.bufferSize; - - if (legalBufferValues.indexOf(bufferSize) === -1) { - if (!config.disableLogs) { - console.log('Legal values for buffer-size are ' + JSON.stringify(legalBufferValues, null, '\t')); - } - } - - if (context.createJavaScriptNode) { - jsAudioNode = context.createJavaScriptNode(bufferSize, numberOfAudioChannels, numberOfAudioChannels); - } else if (context.createScriptProcessor) { - jsAudioNode = context.createScriptProcessor(bufferSize, numberOfAudioChannels, numberOfAudioChannels); - } else { - throw 'WebAudio API has no support on this browser.'; - } - - // connect the stream to the script processor - audioInput.connect(jsAudioNode); - - if (!config.bufferSize) { - bufferSize = jsAudioNode.bufferSize; // device buffer-size - } - - /** - * The sample rate (in sample-frames per second) at which the - * AudioContext handles audio. It is assumed that all AudioNodes - * in the context run at this rate. In making this assumption, - * sample-rate converters or "varispeed" processors are not supported - * in real-time processing. - * The sampleRate parameter describes the sample-rate of the - * linear PCM audio data in the buffer in sample-frames per second. - * An implementation must support sample-rates in at least - * the range 22050 to 96000. - * @property {number} sampleRate - Buffer-size for how frequently the audioprocess event is dispatched. - * @memberof StereoAudioRecorder - * @example - * recorder = new StereoAudioRecorder(mediaStream, { - * sampleRate: 44100 - * }); - */ - var sampleRate = typeof config.sampleRate !== 'undefined' ? config.sampleRate : context.sampleRate || 44100; - - if (sampleRate < 22050 || sampleRate > 96000) { - // Ref: http://stackoverflow.com/a/26303918/552182 - if (!config.disableLogs) { - console.log('sample-rate must be under range 22050 and 96000.'); - } - } - - if (!config.disableLogs) { - if (config.desiredSampRate) { - console.log('Desired sample-rate: ' + config.desiredSampRate); - } - } - - var isPaused = false; - /** - * This method pauses the recording process. - * @method - * @memberof StereoAudioRecorder - * @example - * recorder.pause(); - */ - this.pause = function() { - isPaused = true; - }; - - /** - * This method resumes the recording process. - * @method - * @memberof StereoAudioRecorder - * @example - * recorder.resume(); - */ - this.resume = function() { - if (isMediaStreamActive() === false) { - throw 'Please make sure MediaStream is active.'; - } - - if (!recording) { - if (!config.disableLogs) { - console.log('Seems recording has been restarted.'); - } - this.record(); - return; - } - - isPaused = false; - }; - - /** - * This method resets currently recorded data. - * @method - * @memberof StereoAudioRecorder - * @example - * recorder.clearRecordedData(); - */ - this.clearRecordedData = function() { - config.checkForInactiveTracks = false; - - if (recording) { - this.stop(clearRecordedDataCB); - } - - clearRecordedDataCB(); - }; - - function resetVariables() { - leftchannel = []; - rightchannel = []; - recordingLength = 0; - isAudioProcessStarted = false; - recording = false; - isPaused = false; - context = null; - - self.leftchannel = leftchannel; - self.rightchannel = rightchannel; - self.numberOfAudioChannels = numberOfAudioChannels; - self.desiredSampRate = desiredSampRate; - self.sampleRate = sampleRate; - self.recordingLength = recordingLength; - - intervalsBasedBuffers = { - left: [], - right: [], - recordingLength: 0 - }; - } - - function clearRecordedDataCB() { - if (jsAudioNode) { - jsAudioNode.onaudioprocess = null; - jsAudioNode.disconnect(); - jsAudioNode = null; - } - - if (audioInput) { - audioInput.disconnect(); - audioInput = null; - } - - resetVariables(); - } - - // for debugging - this.name = 'StereoAudioRecorder'; - this.toString = function() { - return this.name; - }; - - var isAudioProcessStarted = false; - - function onAudioProcessDataAvailable(e) { - if (isPaused) { - return; - } - - if (isMediaStreamActive() === false) { - if (!config.disableLogs) { - console.log('MediaStream seems stopped.'); - } - jsAudioNode.disconnect(); - recording = false; - } - - if (!recording) { - if (audioInput) { - audioInput.disconnect(); - audioInput = null; - } - return; - } - - /** - * This method is called on "onaudioprocess" event's first invocation. - * @method {function} onAudioProcessStarted - * @memberof StereoAudioRecorder - * @example - * recorder.onAudioProcessStarted: function() { }; - */ - if (!isAudioProcessStarted) { - isAudioProcessStarted = true; - if (config.onAudioProcessStarted) { - config.onAudioProcessStarted(); - } - - if (config.initCallback) { - config.initCallback(); - } - } - - var left = e.inputBuffer.getChannelData(0); - - // we clone the samples - var chLeft = new Float32Array(left); - leftchannel.push(chLeft); - - if (numberOfAudioChannels === 2) { - var right = e.inputBuffer.getChannelData(1); - var chRight = new Float32Array(right); - rightchannel.push(chRight); - } - - recordingLength += bufferSize; - - // export raw PCM - self.recordingLength = recordingLength; - - if (typeof config.timeSlice !== 'undefined') { - intervalsBasedBuffers.recordingLength += bufferSize; - intervalsBasedBuffers.left.push(chLeft); - - if (numberOfAudioChannels === 2) { - intervalsBasedBuffers.right.push(chRight); - } - } - } - - jsAudioNode.onaudioprocess = onAudioProcessDataAvailable; - - // to prevent self audio to be connected with speakers - if (context.createMediaStreamDestination) { - jsAudioNode.connect(context.createMediaStreamDestination()); - } else { - jsAudioNode.connect(context.destination); - } - - // export raw PCM - this.leftchannel = leftchannel; - this.rightchannel = rightchannel; - this.numberOfAudioChannels = numberOfAudioChannels; - this.desiredSampRate = desiredSampRate; - this.sampleRate = sampleRate; - self.recordingLength = recordingLength; - - // helper for intervals based blobs - var intervalsBasedBuffers = { - left: [], - right: [], - recordingLength: 0 - }; - - // this looper is used to support intervals based blobs (via timeSlice+ondataavailable) - function looper() { - if (!recording || typeof config.ondataavailable !== 'function' || typeof config.timeSlice === 'undefined') { - return; - } - - if (intervalsBasedBuffers.left.length) { - mergeLeftRightBuffers({ - desiredSampRate: desiredSampRate, - sampleRate: sampleRate, - numberOfAudioChannels: numberOfAudioChannels, - internalInterleavedLength: intervalsBasedBuffers.recordingLength, - leftBuffers: intervalsBasedBuffers.left, - rightBuffers: numberOfAudioChannels === 1 ? [] : intervalsBasedBuffers.right - }, function(buffer, view) { - var blob = new Blob([view], { - type: 'audio/wav' - }); - config.ondataavailable(blob); - - setTimeout(looper, config.timeSlice); - }); - - intervalsBasedBuffers = { - left: [], - right: [], - recordingLength: 0 - }; - } else { - setTimeout(looper, config.timeSlice); - } - } -} - -if (typeof RecordRTC !== 'undefined') { - RecordRTC.StereoAudioRecorder = StereoAudioRecorder; -} - -// _________________ -// CanvasRecorder.js - -/** - * CanvasRecorder is a standalone class used by {@link RecordRTC} to bring HTML5-Canvas recording into video WebM. It uses HTML2Canvas library and runs top over {@link Whammy}. - * @summary HTML2Canvas recording into video WebM. - * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} - * @author {@link https://MuazKhan.com|Muaz Khan} - * @typedef CanvasRecorder - * @class - * @example - * var recorder = new CanvasRecorder(htmlElement, { disableLogs: true, useWhammyRecorder: true }); - * recorder.record(); - * recorder.stop(function(blob) { - * video.src = URL.createObjectURL(blob); - * }); - * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} - * @param {HTMLElement} htmlElement - querySelector/getElementById/getElementsByTagName[0]/etc. - * @param {object} config - {disableLogs:true, initCallback: function} - */ - -function CanvasRecorder(htmlElement, config) { - if (typeof html2canvas === 'undefined') { - throw 'Please link: https://www.webrtc-experiment.com/screenshot.js'; - } - - config = config || {}; - if (!config.frameInterval) { - config.frameInterval = 10; - } - - // via DetectRTC.js - var isCanvasSupportsStreamCapturing = false; - ['captureStream', 'mozCaptureStream', 'webkitCaptureStream'].forEach(function(item) { - if (item in document.createElement('canvas')) { - isCanvasSupportsStreamCapturing = true; - } - }); - - var _isChrome = (!!window.webkitRTCPeerConnection || !!window.webkitGetUserMedia) && !!window.chrome; - - var chromeVersion = 50; - var matchArray = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./); - if (_isChrome && matchArray && matchArray[2]) { - chromeVersion = parseInt(matchArray[2], 10); - } - - if (_isChrome && chromeVersion < 52) { - isCanvasSupportsStreamCapturing = false; - } - - if (config.useWhammyRecorder) { - isCanvasSupportsStreamCapturing = false; - } - - var globalCanvas, mediaStreamRecorder; - - if (isCanvasSupportsStreamCapturing) { - if (!config.disableLogs) { - console.log('Your browser supports both MediRecorder API and canvas.captureStream!'); - } - - if (htmlElement instanceof HTMLCanvasElement) { - globalCanvas = htmlElement; - } else if (htmlElement instanceof CanvasRenderingContext2D) { - globalCanvas = htmlElement.canvas; - } else { - throw 'Please pass either HTMLCanvasElement or CanvasRenderingContext2D.'; - } - } else if (!!navigator.mozGetUserMedia) { - if (!config.disableLogs) { - console.error('Canvas recording is NOT supported in Firefox.'); - } - } - - var isRecording; - - /** - * This method records Canvas. - * @method - * @memberof CanvasRecorder - * @example - * recorder.record(); - */ - this.record = function() { - isRecording = true; - - if (isCanvasSupportsStreamCapturing && !config.useWhammyRecorder) { - // CanvasCaptureMediaStream - var canvasMediaStream; - if ('captureStream' in globalCanvas) { - canvasMediaStream = globalCanvas.captureStream(25); // 25 FPS - } else if ('mozCaptureStream' in globalCanvas) { - canvasMediaStream = globalCanvas.mozCaptureStream(25); - } else if ('webkitCaptureStream' in globalCanvas) { - canvasMediaStream = globalCanvas.webkitCaptureStream(25); - } - - try { - var mdStream = new MediaStream(); - mdStream.addTrack(getTracks(canvasMediaStream, 'video')[0]); - canvasMediaStream = mdStream; - } catch (e) {} - - if (!canvasMediaStream) { - throw 'captureStream API are NOT available.'; - } - - // Note: Jan 18, 2016 status is that, - // Firefox MediaRecorder API can't record CanvasCaptureMediaStream object. - mediaStreamRecorder = new MediaStreamRecorder(canvasMediaStream, { - mimeType: config.mimeType || 'video/webm' - }); - mediaStreamRecorder.record(); - } else { - whammy.frames = []; - lastTime = new Date().getTime(); - drawCanvasFrame(); - } - - if (config.initCallback) { - config.initCallback(); - } - }; - - this.getWebPImages = function(callback) { - if (htmlElement.nodeName.toLowerCase() !== 'canvas') { - callback(); - return; - } - - var framesLength = whammy.frames.length; - whammy.frames.forEach(function(frame, idx) { - var framesRemaining = framesLength - idx; - if (!config.disableLogs) { - console.log(framesRemaining + '/' + framesLength + ' frames remaining'); - } - - if (config.onEncodingCallback) { - config.onEncodingCallback(framesRemaining, framesLength); - } - - var webp = frame.image.toDataURL('image/webp', 1); - whammy.frames[idx].image = webp; - }); - - if (!config.disableLogs) { - console.log('Generating WebM'); - } - - callback(); - }; - - /** - * This method stops recording Canvas. - * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee. - * @method - * @memberof CanvasRecorder - * @example - * recorder.stop(function(blob) { - * video.src = URL.createObjectURL(blob); - * }); - */ - this.stop = function(callback) { - isRecording = false; - - var that = this; - - if (isCanvasSupportsStreamCapturing && mediaStreamRecorder) { - mediaStreamRecorder.stop(callback); - return; - } - - this.getWebPImages(function() { - /** - * @property {Blob} blob - Recorded frames in video/webm blob. - * @memberof CanvasRecorder - * @example - * recorder.stop(function() { - * var blob = recorder.blob; - * }); - */ - whammy.compile(function(blob) { - if (!config.disableLogs) { - console.log('Recording finished!'); - } - - that.blob = blob; - - if (that.blob.forEach) { - that.blob = new Blob([], { - type: 'video/webm' - }); - } - - if (callback) { - callback(that.blob); - } - - whammy.frames = []; - }); - }); - }; - - var isPausedRecording = false; - - /** - * This method pauses the recording process. - * @method - * @memberof CanvasRecorder - * @example - * recorder.pause(); - */ - this.pause = function() { - isPausedRecording = true; - - if (mediaStreamRecorder instanceof MediaStreamRecorder) { - mediaStreamRecorder.pause(); - return; - } - }; - - /** - * This method resumes the recording process. - * @method - * @memberof CanvasRecorder - * @example - * recorder.resume(); - */ - this.resume = function() { - isPausedRecording = false; - - if (mediaStreamRecorder instanceof MediaStreamRecorder) { - mediaStreamRecorder.resume(); - return; - } - - if (!isRecording) { - this.record(); - } - }; - - /** - * This method resets currently recorded data. - * @method - * @memberof CanvasRecorder - * @example - * recorder.clearRecordedData(); - */ - this.clearRecordedData = function() { - if (isRecording) { - this.stop(clearRecordedDataCB); - } - clearRecordedDataCB(); - }; - - function clearRecordedDataCB() { - whammy.frames = []; - isRecording = false; - isPausedRecording = false; - } - - // for debugging - this.name = 'CanvasRecorder'; - this.toString = function() { - return this.name; - }; - - function cloneCanvas() { - //create a new canvas - var newCanvas = document.createElement('canvas'); - var context = newCanvas.getContext('2d'); - - //set dimensions - newCanvas.width = htmlElement.width; - newCanvas.height = htmlElement.height; - - //apply the old canvas to the new one - context.drawImage(htmlElement, 0, 0); - - //return the new canvas - return newCanvas; - } - - function drawCanvasFrame() { - if (isPausedRecording) { - lastTime = new Date().getTime(); - return setTimeout(drawCanvasFrame, 500); - } - - if (htmlElement.nodeName.toLowerCase() === 'canvas') { - var duration = new Date().getTime() - lastTime; - // via #206, by Jack i.e. @Seymourr - lastTime = new Date().getTime(); - - whammy.frames.push({ - image: cloneCanvas(), - duration: duration - }); - - if (isRecording) { - setTimeout(drawCanvasFrame, config.frameInterval); - } - return; - } - - html2canvas(htmlElement, { - grabMouse: typeof config.showMousePointer === 'undefined' || config.showMousePointer, - onrendered: function(canvas) { - var duration = new Date().getTime() - lastTime; - if (!duration) { - return setTimeout(drawCanvasFrame, config.frameInterval); - } - - // via #206, by Jack i.e. @Seymourr - lastTime = new Date().getTime(); - - whammy.frames.push({ - image: canvas.toDataURL('image/webp', 1), - duration: duration - }); - - if (isRecording) { - setTimeout(drawCanvasFrame, config.frameInterval); - } - } - }); - } - - var lastTime = new Date().getTime(); - - var whammy = new Whammy.Video(100); -} - -if (typeof RecordRTC !== 'undefined') { - RecordRTC.CanvasRecorder = CanvasRecorder; -} - -// _________________ -// WhammyRecorder.js - -/** - * WhammyRecorder is a standalone class used by {@link RecordRTC} to bring video recording in Chrome. It runs top over {@link Whammy}. - * @summary Video recording feature in Chrome. - * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} - * @author {@link https://MuazKhan.com|Muaz Khan} - * @typedef WhammyRecorder - * @class - * @example - * var recorder = new WhammyRecorder(mediaStream); - * recorder.record(); - * recorder.stop(function(blob) { - * video.src = URL.createObjectURL(blob); - * }); - * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} - * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API. - * @param {object} config - {disableLogs: true, initCallback: function, video: HTMLVideoElement, etc.} - */ - -function WhammyRecorder(mediaStream, config) { - - config = config || {}; - - if (!config.frameInterval) { - config.frameInterval = 10; - } - - if (!config.disableLogs) { - console.log('Using frames-interval:', config.frameInterval); - } - - /** - * This method records video. - * @method - * @memberof WhammyRecorder - * @example - * recorder.record(); - */ - this.record = function() { - if (!config.width) { - config.width = 320; - } - - if (!config.height) { - config.height = 240; - } - - if (!config.video) { - config.video = { - width: config.width, - height: config.height - }; - } - - if (!config.canvas) { - config.canvas = { - width: config.width, - height: config.height - }; - } - - canvas.width = config.canvas.width || 320; - canvas.height = config.canvas.height || 240; - - context = canvas.getContext('2d'); - - // setting defaults - if (config.video && config.video instanceof HTMLVideoElement) { - video = config.video.cloneNode(); - - if (config.initCallback) { - config.initCallback(); - } - } else { - video = document.createElement('video'); - - setSrcObject(mediaStream, video); - - video.onloadedmetadata = function() { // "onloadedmetadata" may NOT work in FF? - if (config.initCallback) { - config.initCallback(); - } - }; - - video.width = config.video.width; - video.height = config.video.height; - } - - video.muted = true; - video.play(); - - lastTime = new Date().getTime(); - whammy = new Whammy.Video(); - - if (!config.disableLogs) { - console.log('canvas resolutions', canvas.width, '*', canvas.height); - console.log('video width/height', video.width || canvas.width, '*', video.height || canvas.height); - } - - drawFrames(config.frameInterval); - }; - - /** - * Draw and push frames to Whammy - * @param {integer} frameInterval - set minimum interval (in milliseconds) between each time we push a frame to Whammy - */ - function drawFrames(frameInterval) { - frameInterval = typeof frameInterval !== 'undefined' ? frameInterval : 10; - - var duration = new Date().getTime() - lastTime; - if (!duration) { - return setTimeout(drawFrames, frameInterval, frameInterval); - } - - if (isPausedRecording) { - lastTime = new Date().getTime(); - return setTimeout(drawFrames, 100); - } - - // via #206, by Jack i.e. @Seymourr - lastTime = new Date().getTime(); - - if (video.paused) { - // via: https://github.com/muaz-khan/WebRTC-Experiment/pull/316 - // Tweak for Android Chrome - video.play(); - } - - context.drawImage(video, 0, 0, canvas.width, canvas.height); - whammy.frames.push({ - duration: duration, - image: canvas.toDataURL('image/webp') - }); - - if (!isStopDrawing) { - setTimeout(drawFrames, frameInterval, frameInterval); - } - } - - function asyncLoop(o) { - var i = -1, - length = o.length; - - (function loop() { - i++; - if (i === length) { - o.callback(); - return; - } - - // "setTimeout" added by Jim McLeod - setTimeout(function() { - o.functionToLoop(loop, i); - }, 1); - })(); - } - - - /** - * remove black frames from the beginning to the specified frame - * @param {Array} _frames - array of frames to be checked - * @param {number} _framesToCheck - number of frame until check will be executed (-1 - will drop all frames until frame not matched will be found) - * @param {number} _pixTolerance - 0 - very strict (only black pixel color) ; 1 - all - * @param {number} _frameTolerance - 0 - very strict (only black frame color) ; 1 - all - * @returns {Array} - array of frames - */ - // pull#293 by @volodalexey - function dropBlackFrames(_frames, _framesToCheck, _pixTolerance, _frameTolerance, callback) { - var localCanvas = document.createElement('canvas'); - localCanvas.width = canvas.width; - localCanvas.height = canvas.height; - var context2d = localCanvas.getContext('2d'); - var resultFrames = []; - - var checkUntilNotBlack = _framesToCheck === -1; - var endCheckFrame = (_framesToCheck && _framesToCheck > 0 && _framesToCheck <= _frames.length) ? - _framesToCheck : _frames.length; - var sampleColor = { - r: 0, - g: 0, - b: 0 - }; - var maxColorDifference = Math.sqrt( - Math.pow(255, 2) + - Math.pow(255, 2) + - Math.pow(255, 2) - ); - var pixTolerance = _pixTolerance && _pixTolerance >= 0 && _pixTolerance <= 1 ? _pixTolerance : 0; - var frameTolerance = _frameTolerance && _frameTolerance >= 0 && _frameTolerance <= 1 ? _frameTolerance : 0; - var doNotCheckNext = false; - - asyncLoop({ - length: endCheckFrame, - functionToLoop: function(loop, f) { - var matchPixCount, endPixCheck, maxPixCount; - - var finishImage = function() { - if (!doNotCheckNext && maxPixCount - matchPixCount <= maxPixCount * frameTolerance) { - // console.log('removed black frame : ' + f + ' ; frame duration ' + _frames[f].duration); - } else { - // console.log('frame is passed : ' + f); - if (checkUntilNotBlack) { - doNotCheckNext = true; - } - resultFrames.push(_frames[f]); - } - loop(); - }; - - if (!doNotCheckNext) { - var image = new Image(); - image.onload = function() { - context2d.drawImage(image, 0, 0, canvas.width, canvas.height); - var imageData = context2d.getImageData(0, 0, canvas.width, canvas.height); - matchPixCount = 0; - endPixCheck = imageData.data.length; - maxPixCount = imageData.data.length / 4; - - for (var pix = 0; pix < endPixCheck; pix += 4) { - var currentColor = { - r: imageData.data[pix], - g: imageData.data[pix + 1], - b: imageData.data[pix + 2] - }; - var colorDifference = Math.sqrt( - Math.pow(currentColor.r - sampleColor.r, 2) + - Math.pow(currentColor.g - sampleColor.g, 2) + - Math.pow(currentColor.b - sampleColor.b, 2) - ); - // difference in color it is difference in color vectors (r1,g1,b1) <=> (r2,g2,b2) - if (colorDifference <= maxColorDifference * pixTolerance) { - matchPixCount++; - } - } - finishImage(); - }; - image.src = _frames[f].image; - } else { - finishImage(); - } - }, - callback: function() { - resultFrames = resultFrames.concat(_frames.slice(endCheckFrame)); - - if (resultFrames.length <= 0) { - // at least one last frame should be available for next manipulation - // if total duration of all frames will be < 1000 than ffmpeg doesn't work well... - resultFrames.push(_frames[_frames.length - 1]); - } - callback(resultFrames); - } - }); - } - - var isStopDrawing = false; - - /** - * This method stops recording video. - * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee. - * @method - * @memberof WhammyRecorder - * @example - * recorder.stop(function(blob) { - * video.src = URL.createObjectURL(blob); - * }); - */ - this.stop = function(callback) { - callback = callback || function() {}; - - isStopDrawing = true; - - var _this = this; - // analyse of all frames takes some time! - setTimeout(function() { - // e.g. dropBlackFrames(frames, 10, 1, 1) - will cut all 10 frames - // e.g. dropBlackFrames(frames, 10, 0.5, 0.5) - will analyse 10 frames - // e.g. dropBlackFrames(frames, 10) === dropBlackFrames(frames, 10, 0, 0) - will analyse 10 frames with strict black color - dropBlackFrames(whammy.frames, -1, null, null, function(frames) { - whammy.frames = frames; - - // to display advertisement images! - if (config.advertisement && config.advertisement.length) { - whammy.frames = config.advertisement.concat(whammy.frames); - } - - /** - * @property {Blob} blob - Recorded frames in video/webm blob. - * @memberof WhammyRecorder - * @example - * recorder.stop(function() { - * var blob = recorder.blob; - * }); - */ - whammy.compile(function(blob) { - _this.blob = blob; - - if (_this.blob.forEach) { - _this.blob = new Blob([], { - type: 'video/webm' - }); - } - - if (callback) { - callback(_this.blob); - } - }); - }); - }, 10); - }; - - var isPausedRecording = false; - - /** - * This method pauses the recording process. - * @method - * @memberof WhammyRecorder - * @example - * recorder.pause(); - */ - this.pause = function() { - isPausedRecording = true; - }; - - /** - * This method resumes the recording process. - * @method - * @memberof WhammyRecorder - * @example - * recorder.resume(); - */ - this.resume = function() { - isPausedRecording = false; - - if (isStopDrawing) { - this.record(); - } - }; - - /** - * This method resets currently recorded data. - * @method - * @memberof WhammyRecorder - * @example - * recorder.clearRecordedData(); - */ - this.clearRecordedData = function() { - if (!isStopDrawing) { - this.stop(clearRecordedDataCB); - } - clearRecordedDataCB(); - }; - - function clearRecordedDataCB() { - whammy.frames = []; - isStopDrawing = true; - isPausedRecording = false; - } - - // for debugging - this.name = 'WhammyRecorder'; - this.toString = function() { - return this.name; - }; - - var canvas = document.createElement('canvas'); - var context = canvas.getContext('2d'); - - var video; - var lastTime; - var whammy; -} - -if (typeof RecordRTC !== 'undefined') { - RecordRTC.WhammyRecorder = WhammyRecorder; -} - -// https://github.com/antimatter15/whammy/blob/master/LICENSE -// _________ -// Whammy.js - -// todo: Firefox now supports webp for webm containers! -// their MediaRecorder implementation works well! -// should we provide an option to record via Whammy.js or MediaRecorder API is a better solution? - -/** - * Whammy is a standalone class used by {@link RecordRTC} to bring video recording in Chrome. It is written by {@link https://github.com/antimatter15|antimatter15} - * @summary A real time javascript webm encoder based on a canvas hack. - * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} - * @author {@link https://MuazKhan.com|Muaz Khan} - * @typedef Whammy - * @class - * @example - * var recorder = new Whammy().Video(15); - * recorder.add(context || canvas || dataURL); - * var output = recorder.compile(); - * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} - */ - -var Whammy = (function() { - // a more abstract-ish API - - function WhammyVideo(duration) { - this.frames = []; - this.duration = duration || 1; - this.quality = 0.8; - } - - /** - * Pass Canvas or Context or image/webp(string) to {@link Whammy} encoder. - * @method - * @memberof Whammy - * @example - * recorder = new Whammy().Video(0.8, 100); - * recorder.add(canvas || context || 'image/webp'); - * @param {string} frame - Canvas || Context || image/webp - * @param {number} duration - Stick a duration (in milliseconds) - */ - WhammyVideo.prototype.add = function(frame, duration) { - if ('canvas' in frame) { //CanvasRenderingContext2D - frame = frame.canvas; - } - - if ('toDataURL' in frame) { - frame = frame.toDataURL('image/webp', this.quality); - } - - if (!(/^data:image\/webp;base64,/ig).test(frame)) { - throw 'Input must be formatted properly as a base64 encoded DataURI of type image/webp'; - } - this.frames.push({ - image: frame, - duration: duration || this.duration - }); - }; - - function processInWebWorker(_function) { - var blob = URL.createObjectURL(new Blob([_function.toString(), - 'this.onmessage = function (eee) {' + _function.name + '(eee.data);}' - ], { - type: 'application/javascript' - })); - - var worker = new Worker(blob); - URL.revokeObjectURL(blob); - return worker; - } - - function whammyInWebWorker(frames) { - function ArrayToWebM(frames) { - var info = checkFrames(frames); - if (!info) { - return []; - } - - var clusterMaxDuration = 30000; - - var EBML = [{ - 'id': 0x1a45dfa3, // EBML - 'data': [{ - 'data': 1, - 'id': 0x4286 // EBMLVersion - }, { - 'data': 1, - 'id': 0x42f7 // EBMLReadVersion - }, { - 'data': 4, - 'id': 0x42f2 // EBMLMaxIDLength - }, { - 'data': 8, - 'id': 0x42f3 // EBMLMaxSizeLength - }, { - 'data': 'webm', - 'id': 0x4282 // DocType - }, { - 'data': 2, - 'id': 0x4287 // DocTypeVersion - }, { - 'data': 2, - 'id': 0x4285 // DocTypeReadVersion - }] - }, { - 'id': 0x18538067, // Segment - 'data': [{ - 'id': 0x1549a966, // Info - 'data': [{ - 'data': 1e6, //do things in millisecs (num of nanosecs for duration scale) - 'id': 0x2ad7b1 // TimecodeScale - }, { - 'data': 'whammy', - 'id': 0x4d80 // MuxingApp - }, { - 'data': 'whammy', - 'id': 0x5741 // WritingApp - }, { - 'data': doubleToString(info.duration), - 'id': 0x4489 // Duration - }] - }, { - 'id': 0x1654ae6b, // Tracks - 'data': [{ - 'id': 0xae, // TrackEntry - 'data': [{ - 'data': 1, - 'id': 0xd7 // TrackNumber - }, { - 'data': 1, - 'id': 0x73c5 // TrackUID - }, { - 'data': 0, - 'id': 0x9c // FlagLacing - }, { - 'data': 'und', - 'id': 0x22b59c // Language - }, { - 'data': 'V_VP8', - 'id': 0x86 // CodecID - }, { - 'data': 'VP8', - 'id': 0x258688 // CodecName - }, { - 'data': 1, - 'id': 0x83 // TrackType - }, { - 'id': 0xe0, // Video - 'data': [{ - 'data': info.width, - 'id': 0xb0 // PixelWidth - }, { - 'data': info.height, - 'id': 0xba // PixelHeight - }] - }] - }] - }] - }]; - - //Generate clusters (max duration) - var frameNumber = 0; - var clusterTimecode = 0; - while (frameNumber < frames.length) { - - var clusterFrames = []; - var clusterDuration = 0; - do { - clusterFrames.push(frames[frameNumber]); - clusterDuration += frames[frameNumber].duration; - frameNumber++; - } while (frameNumber < frames.length && clusterDuration < clusterMaxDuration); - - var clusterCounter = 0; - var cluster = { - 'id': 0x1f43b675, // Cluster - 'data': getClusterData(clusterTimecode, clusterCounter, clusterFrames) - }; //Add cluster to segment - EBML[1].data.push(cluster); - clusterTimecode += clusterDuration; - } - - return generateEBML(EBML); - } - - function getClusterData(clusterTimecode, clusterCounter, clusterFrames) { - return [{ - 'data': clusterTimecode, - 'id': 0xe7 // Timecode - }].concat(clusterFrames.map(function(webp) { - var block = makeSimpleBlock({ - discardable: 0, - frame: webp.data.slice(4), - invisible: 0, - keyframe: 1, - lacing: 0, - trackNum: 1, - timecode: Math.round(clusterCounter) - }); - clusterCounter += webp.duration; - return { - data: block, - id: 0xa3 - }; - })); - } - - // sums the lengths of all the frames and gets the duration - - function checkFrames(frames) { - if (!frames[0]) { - postMessage({ - error: 'Something went wrong. Maybe WebP format is not supported in the current browser.' - }); - return; - } - - var width = frames[0].width, - height = frames[0].height, - duration = frames[0].duration; - - for (var i = 1; i < frames.length; i++) { - duration += frames[i].duration; - } - return { - duration: duration, - width: width, - height: height - }; - } - - function numToBuffer(num) { - var parts = []; - while (num > 0) { - parts.push(num & 0xff); - num = num >> 8; - } - return new Uint8Array(parts.reverse()); - } - - function strToBuffer(str) { - return new Uint8Array(str.split('').map(function(e) { - return e.charCodeAt(0); - })); - } - - function bitsToBuffer(bits) { - var data = []; - var pad = (bits.length % 8) ? (new Array(1 + 8 - (bits.length % 8))).join('0') : ''; - bits = pad + bits; - for (var i = 0; i < bits.length; i += 8) { - data.push(parseInt(bits.substr(i, 8), 2)); - } - return new Uint8Array(data); - } - - function generateEBML(json) { - var ebml = []; - for (var i = 0; i < json.length; i++) { - var data = json[i].data; - - if (typeof data === 'object') { - data = generateEBML(data); - } - - if (typeof data === 'number') { - data = bitsToBuffer(data.toString(2)); - } - - if (typeof data === 'string') { - data = strToBuffer(data); - } - - var len = data.size || data.byteLength || data.length; - var zeroes = Math.ceil(Math.ceil(Math.log(len) / Math.log(2)) / 8); - var sizeToString = len.toString(2); - var padded = (new Array((zeroes * 7 + 7 + 1) - sizeToString.length)).join('0') + sizeToString; - var size = (new Array(zeroes)).join('0') + '1' + padded; - - ebml.push(numToBuffer(json[i].id)); - ebml.push(bitsToBuffer(size)); - ebml.push(data); - } - - return new Blob(ebml, { - type: 'video/webm' - }); - } - - function toBinStrOld(bits) { - var data = ''; - var pad = (bits.length % 8) ? (new Array(1 + 8 - (bits.length % 8))).join('0') : ''; - bits = pad + bits; - for (var i = 0; i < bits.length; i += 8) { - data += String.fromCharCode(parseInt(bits.substr(i, 8), 2)); - } - return data; - } - - function makeSimpleBlock(data) { - var flags = 0; - - if (data.keyframe) { - flags |= 128; - } - - if (data.invisible) { - flags |= 8; - } - - if (data.lacing) { - flags |= (data.lacing << 1); - } - - if (data.discardable) { - flags |= 1; - } - - if (data.trackNum > 127) { - throw 'TrackNumber > 127 not supported'; - } - - var out = [data.trackNum | 0x80, data.timecode >> 8, data.timecode & 0xff, flags].map(function(e) { - return String.fromCharCode(e); - }).join('') + data.frame; - - return out; - } - - function parseWebP(riff) { - var VP8 = riff.RIFF[0].WEBP[0]; - - var frameStart = VP8.indexOf('\x9d\x01\x2a'); // A VP8 keyframe starts with the 0x9d012a header - for (var i = 0, c = []; i < 4; i++) { - c[i] = VP8.charCodeAt(frameStart + 3 + i); - } - - var width, height, tmp; - - //the code below is literally copied verbatim from the bitstream spec - tmp = (c[1] << 8) | c[0]; - width = tmp & 0x3FFF; - tmp = (c[3] << 8) | c[2]; - height = tmp & 0x3FFF; - return { - width: width, - height: height, - data: VP8, - riff: riff - }; - } - - function getStrLength(string, offset) { - return parseInt(string.substr(offset + 4, 4).split('').map(function(i) { - var unpadded = i.charCodeAt(0).toString(2); - return (new Array(8 - unpadded.length + 1)).join('0') + unpadded; - }).join(''), 2); - } - - function parseRIFF(string) { - var offset = 0; - var chunks = {}; - - while (offset < string.length) { - var id = string.substr(offset, 4); - var len = getStrLength(string, offset); - var data = string.substr(offset + 4 + 4, len); - offset += 4 + 4 + len; - chunks[id] = chunks[id] || []; - - if (id === 'RIFF' || id === 'LIST') { - chunks[id].push(parseRIFF(data)); - } else { - chunks[id].push(data); - } - } - return chunks; - } - - function doubleToString(num) { - return [].slice.call( - new Uint8Array((new Float64Array([num])).buffer), 0).map(function(e) { - return String.fromCharCode(e); - }).reverse().join(''); - } - - var webm = new ArrayToWebM(frames.map(function(frame) { - var webp = parseWebP(parseRIFF(atob(frame.image.slice(23)))); - webp.duration = frame.duration; - return webp; - })); - - postMessage(webm); - } - - /** - * Encodes frames in WebM container. It uses WebWorkinvoke to invoke 'ArrayToWebM' method. - * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee. - * @method - * @memberof Whammy - * @example - * recorder = new Whammy().Video(0.8, 100); - * recorder.compile(function(blob) { - * // blob.size - blob.type - * }); - */ - WhammyVideo.prototype.compile = function(callback) { - var webWorker = processInWebWorker(whammyInWebWorker); - - webWorker.onmessage = function(event) { - if (event.data.error) { - console.error(event.data.error); - return; - } - callback(event.data); - }; - - webWorker.postMessage(this.frames); - }; - - return { - /** - * A more abstract-ish API. - * @method - * @memberof Whammy - * @example - * recorder = new Whammy().Video(0.8, 100); - * @param {?number} speed - 0.8 - * @param {?number} quality - 100 - */ - Video: WhammyVideo - }; -})(); - -if (typeof RecordRTC !== 'undefined') { - RecordRTC.Whammy = Whammy; -} - -// ______________ (indexed-db) -// DiskStorage.js - -/** - * DiskStorage is a standalone object used by {@link RecordRTC} to store recorded blobs in IndexedDB storage. - * @summary Writing blobs into IndexedDB. - * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} - * @author {@link https://MuazKhan.com|Muaz Khan} - * @example - * DiskStorage.Store({ - * audioBlob: yourAudioBlob, - * videoBlob: yourVideoBlob, - * gifBlob : yourGifBlob - * }); - * DiskStorage.Fetch(function(dataURL, type) { - * if(type === 'audioBlob') { } - * if(type === 'videoBlob') { } - * if(type === 'gifBlob') { } - * }); - * // DiskStorage.dataStoreName = 'recordRTC'; - * // DiskStorage.onError = function(error) { }; - * @property {function} init - This method must be called once to initialize IndexedDB ObjectStore. Though, it is auto-used internally. - * @property {function} Fetch - This method fetches stored blobs from IndexedDB. - * @property {function} Store - This method stores blobs in IndexedDB. - * @property {function} onError - This function is invoked for any known/unknown error. - * @property {string} dataStoreName - Name of the ObjectStore created in IndexedDB storage. - * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} - */ - - -var DiskStorage = { - /** - * This method must be called once to initialize IndexedDB ObjectStore. Though, it is auto-used internally. - * @method - * @memberof DiskStorage - * @internal - * @example - * DiskStorage.init(); - */ - init: function() { - var self = this; - - if (typeof indexedDB === 'undefined' || typeof indexedDB.open === 'undefined') { - console.error('IndexedDB API are not available in this browser.'); - return; - } - - var dbVersion = 1; - var dbName = this.dbName || location.href.replace(/\/|:|#|%|\.|\[|\]/g, ''), - db; - var request = indexedDB.open(dbName, dbVersion); - - function createObjectStore(dataBase) { - dataBase.createObjectStore(self.dataStoreName); - } - - function putInDB() { - var transaction = db.transaction([self.dataStoreName], 'readwrite'); - - if (self.videoBlob) { - transaction.objectStore(self.dataStoreName).put(self.videoBlob, 'videoBlob'); - } - - if (self.gifBlob) { - transaction.objectStore(self.dataStoreName).put(self.gifBlob, 'gifBlob'); - } - - if (self.audioBlob) { - transaction.objectStore(self.dataStoreName).put(self.audioBlob, 'audioBlob'); - } - - function getFromStore(portionName) { - transaction.objectStore(self.dataStoreName).get(portionName).onsuccess = function(event) { - if (self.callback) { - self.callback(event.target.result, portionName); - } - }; - } - - getFromStore('audioBlob'); - getFromStore('videoBlob'); - getFromStore('gifBlob'); - } - - request.onerror = self.onError; - - request.onsuccess = function() { - db = request.result; - db.onerror = self.onError; - - if (db.setVersion) { - if (db.version !== dbVersion) { - var setVersion = db.setVersion(dbVersion); - setVersion.onsuccess = function() { - createObjectStore(db); - putInDB(); - }; - } else { - putInDB(); - } - } else { - putInDB(); - } - }; - request.onupgradeneeded = function(event) { - createObjectStore(event.target.result); - }; - }, - /** - * This method fetches stored blobs from IndexedDB. - * @method - * @memberof DiskStorage - * @internal - * @example - * DiskStorage.Fetch(function(dataURL, type) { - * if(type === 'audioBlob') { } - * if(type === 'videoBlob') { } - * if(type === 'gifBlob') { } - * }); - */ - Fetch: function(callback) { - this.callback = callback; - this.init(); - - return this; - }, - /** - * This method stores blobs in IndexedDB. - * @method - * @memberof DiskStorage - * @internal - * @example - * DiskStorage.Store({ - * audioBlob: yourAudioBlob, - * videoBlob: yourVideoBlob, - * gifBlob : yourGifBlob - * }); - */ - Store: function(config) { - this.audioBlob = config.audioBlob; - this.videoBlob = config.videoBlob; - this.gifBlob = config.gifBlob; - - this.init(); - - return this; - }, - /** - * This function is invoked for any known/unknown error. - * @method - * @memberof DiskStorage - * @internal - * @example - * DiskStorage.onError = function(error){ - * alerot( JSON.stringify(error) ); - * }; - */ - onError: function(error) { - console.error(JSON.stringify(error, null, '\t')); - }, - - /** - * @property {string} dataStoreName - Name of the ObjectStore created in IndexedDB storage. - * @memberof DiskStorage - * @internal - * @example - * DiskStorage.dataStoreName = 'recordRTC'; - */ - dataStoreName: 'recordRTC', - dbName: null -}; - -if (typeof RecordRTC !== 'undefined') { - RecordRTC.DiskStorage = DiskStorage; -} - -// ______________ -// GifRecorder.js - -/** - * GifRecorder is standalone calss used by {@link RecordRTC} to record video or canvas into animated gif. - * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} - * @author {@link https://MuazKhan.com|Muaz Khan} - * @typedef GifRecorder - * @class - * @example - * var recorder = new GifRecorder(mediaStream || canvas || context, { onGifPreview: function, onGifRecordingStarted: function, width: 1280, height: 720, frameRate: 200, quality: 10 }); - * recorder.record(); - * recorder.stop(function(blob) { - * img.src = URL.createObjectURL(blob); - * }); - * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} - * @param {MediaStream} mediaStream - MediaStream object or HTMLCanvasElement or CanvasRenderingContext2D. - * @param {object} config - {disableLogs:true, initCallback: function, width: 320, height: 240, frameRate: 200, quality: 10} - */ - -function GifRecorder(mediaStream, config) { - if (typeof GIFEncoder === 'undefined') { - var script = document.createElement('script'); - script.src = 'https://www.webrtc-experiment.com/gif-recorder.js'; - (document.body || document.documentElement).appendChild(script); - } - - config = config || {}; - - var isHTMLObject = mediaStream instanceof CanvasRenderingContext2D || mediaStream instanceof HTMLCanvasElement; - - /** - * This method records MediaStream. - * @method - * @memberof GifRecorder - * @example - * recorder.record(); - */ - this.record = function() { - if (typeof GIFEncoder === 'undefined') { - setTimeout(self.record, 1000); - return; - } - - if (!isLoadedMetaData) { - setTimeout(self.record, 1000); - return; - } - - if (!isHTMLObject) { - if (!config.width) { - config.width = video.offsetWidth || 320; - } - - if (!config.height) { - config.height = video.offsetHeight || 240; - } - - if (!config.video) { - config.video = { - width: config.width, - height: config.height - }; - } - - if (!config.canvas) { - config.canvas = { - width: config.width, - height: config.height - }; - } - - canvas.width = config.canvas.width || 320; - canvas.height = config.canvas.height || 240; - - video.width = config.video.width || 320; - video.height = config.video.height || 240; - } - - // external library to record as GIF images - gifEncoder = new GIFEncoder(); - - // void setRepeat(int iter) - // Sets the number of times the set of GIF frames should be played. - // Default is 1; 0 means play indefinitely. - gifEncoder.setRepeat(0); - - // void setFrameRate(Number fps) - // Sets frame rate in frames per second. - // Equivalent to setDelay(1000/fps). - // Using "setDelay" instead of "setFrameRate" - gifEncoder.setDelay(config.frameRate || 200); - - // void setQuality(int quality) - // Sets quality of color quantization (conversion of images to the - // maximum 256 colors allowed by the GIF specification). - // Lower values (minimum = 1) produce better colors, - // but slow processing significantly. 10 is the default, - // and produces good color mapping at reasonable speeds. - // Values greater than 20 do not yield significant improvements in speed. - gifEncoder.setQuality(config.quality || 10); - - // Boolean start() - // This writes the GIF Header and returns false if it fails. - gifEncoder.start(); - - if (typeof config.onGifRecordingStarted === 'function') { - config.onGifRecordingStarted(); - } - - startTime = Date.now(); - - function drawVideoFrame(time) { - if (self.clearedRecordedData === true) { - return; - } - - if (isPausedRecording) { - return setTimeout(function() { - drawVideoFrame(time); - }, 100); - } - - lastAnimationFrame = requestAnimationFrame(drawVideoFrame); - - if (typeof lastFrameTime === undefined) { - lastFrameTime = time; - } - - // ~10 fps - if (time - lastFrameTime < 90) { - return; - } - - if (!isHTMLObject && video.paused) { - // via: https://github.com/muaz-khan/WebRTC-Experiment/pull/316 - // Tweak for Android Chrome - video.play(); - } - - if (!isHTMLObject) { - context.drawImage(video, 0, 0, canvas.width, canvas.height); - } - - if (config.onGifPreview) { - config.onGifPreview(canvas.toDataURL('image/png')); - } - - gifEncoder.addFrame(context); - lastFrameTime = time; - } - - lastAnimationFrame = requestAnimationFrame(drawVideoFrame); - - if (config.initCallback) { - config.initCallback(); - } - }; - - /** - * This method stops recording MediaStream. - * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee. - * @method - * @memberof GifRecorder - * @example - * recorder.stop(function(blob) { - * img.src = URL.createObjectURL(blob); - * }); - */ - this.stop = function(callback) { - callback = callback || function() {}; - - if (lastAnimationFrame) { - cancelAnimationFrame(lastAnimationFrame); - } - - endTime = Date.now(); - - /** - * @property {Blob} blob - The recorded blob object. - * @memberof GifRecorder - * @example - * recorder.stop(function(){ - * var blob = recorder.blob; - * }); - */ - this.blob = new Blob([new Uint8Array(gifEncoder.stream().bin)], { - type: 'image/gif' - }); - - callback(this.blob); - - // bug: find a way to clear old recorded blobs - gifEncoder.stream().bin = []; - }; - - var isPausedRecording = false; - - /** - * This method pauses the recording process. - * @method - * @memberof GifRecorder - * @example - * recorder.pause(); - */ - this.pause = function() { - isPausedRecording = true; - }; - - /** - * This method resumes the recording process. - * @method - * @memberof GifRecorder - * @example - * recorder.resume(); - */ - this.resume = function() { - isPausedRecording = false; - }; - - /** - * This method resets currently recorded data. - * @method - * @memberof GifRecorder - * @example - * recorder.clearRecordedData(); - */ - this.clearRecordedData = function() { - self.clearedRecordedData = true; - clearRecordedDataCB(); - }; - - function clearRecordedDataCB() { - if (gifEncoder) { - gifEncoder.stream().bin = []; - } - } - - // for debugging - this.name = 'GifRecorder'; - this.toString = function() { - return this.name; - }; - - var canvas = document.createElement('canvas'); - var context = canvas.getContext('2d'); - - if (isHTMLObject) { - if (mediaStream instanceof CanvasRenderingContext2D) { - context = mediaStream; - canvas = context.canvas; - } else if (mediaStream instanceof HTMLCanvasElement) { - context = mediaStream.getContext('2d'); - canvas = mediaStream; - } - } - - var isLoadedMetaData = true; - - if (!isHTMLObject) { - var video = document.createElement('video'); - video.muted = true; - video.autoplay = true; - video.playsInline = true; - - isLoadedMetaData = false; - video.onloadedmetadata = function() { - isLoadedMetaData = true; - }; - - setSrcObject(mediaStream, video); - - video.play(); - } - - var lastAnimationFrame = null; - var startTime, endTime, lastFrameTime; - - var gifEncoder; - - var self = this; -} - -if (typeof RecordRTC !== 'undefined') { - RecordRTC.GifRecorder = GifRecorder; -} - -// Last time updated: 2019-06-21 4:09:42 AM UTC - -// ________________________ -// MultiStreamsMixer v1.2.2 - -// Open-Sourced: https://github.com/muaz-khan/MultiStreamsMixer - -// -------------------------------------------------- -// Muaz Khan - www.MuazKhan.com -// MIT License - www.WebRTC-Experiment.com/licence -// -------------------------------------------------- - -function MultiStreamsMixer(arrayOfMediaStreams, elementClass) { - - var browserFakeUserAgent = 'Fake/5.0 (FakeOS) AppleWebKit/123 (KHTML, like Gecko) Fake/12.3.4567.89 Fake/123.45'; - - (function(that) { - if (typeof RecordRTC !== 'undefined') { - return; - } - - if (!that) { - return; - } - - if (typeof window !== 'undefined') { - return; - } - - if (typeof global === 'undefined') { - return; - } - - global.navigator = { - userAgent: browserFakeUserAgent, - getUserMedia: function() {} - }; - - if (!global.console) { - global.console = {}; - } - - if (typeof global.console.log === 'undefined' || typeof global.console.error === 'undefined') { - global.console.error = global.console.log = global.console.log || function() { - console.log(arguments); - }; - } - - if (typeof document === 'undefined') { - /*global document:true */ - that.document = { - documentElement: { - appendChild: function() { - return ''; - } - } - }; - - document.createElement = document.captureStream = document.mozCaptureStream = function() { - var obj = { - getContext: function() { - return obj; - }, - play: function() {}, - pause: function() {}, - drawImage: function() {}, - toDataURL: function() { - return ''; - }, - style: {} - }; - return obj; - }; - - that.HTMLVideoElement = function() {}; - } - - if (typeof location === 'undefined') { - /*global location:true */ - that.location = { - protocol: 'file:', - href: '', - hash: '' - }; - } - - if (typeof screen === 'undefined') { - /*global screen:true */ - that.screen = { - width: 0, - height: 0 - }; - } - - if (typeof URL === 'undefined') { - /*global screen:true */ - that.URL = { - createObjectURL: function() { - return ''; - }, - revokeObjectURL: function() { - return ''; - } - }; - } - - /*global window:true */ - that.window = global; - })(typeof global !== 'undefined' ? global : null); - - // requires: chrome://flags/#enable-experimental-web-platform-features - - elementClass = elementClass || 'multi-streams-mixer'; - - var videos = []; - var isStopDrawingFrames = false; - - var canvas = document.createElement('canvas'); - var context = canvas.getContext('2d'); - canvas.style.opacity = 0; - canvas.style.position = 'absolute'; - canvas.style.zIndex = -1; - canvas.style.top = '-1000em'; - canvas.style.left = '-1000em'; - canvas.className = elementClass; - (document.body || document.documentElement).appendChild(canvas); - - this.disableLogs = false; - this.frameInterval = 10; - - this.width = 360; - this.height = 240; - - // use gain node to prevent echo - this.useGainNode = true; - - var self = this; - - // _____________________________ - // Cross-Browser-Declarations.js - - // WebAudio API representer - var AudioContext = window.AudioContext; - - if (typeof AudioContext === 'undefined') { - if (typeof webkitAudioContext !== 'undefined') { - /*global AudioContext:true */ - AudioContext = webkitAudioContext; - } - - if (typeof mozAudioContext !== 'undefined') { - /*global AudioContext:true */ - AudioContext = mozAudioContext; - } - } - - /*jshint -W079 */ - var URL = window.URL; - - if (typeof URL === 'undefined' && typeof webkitURL !== 'undefined') { - /*global URL:true */ - URL = webkitURL; - } - - if (typeof navigator !== 'undefined' && typeof navigator.getUserMedia === 'undefined') { // maybe window.navigator? - if (typeof navigator.webkitGetUserMedia !== 'undefined') { - navigator.getUserMedia = navigator.webkitGetUserMedia; - } - - if (typeof navigator.mozGetUserMedia !== 'undefined') { - navigator.getUserMedia = navigator.mozGetUserMedia; - } - } - - var MediaStream = window.MediaStream; - - if (typeof MediaStream === 'undefined' && typeof webkitMediaStream !== 'undefined') { - MediaStream = webkitMediaStream; - } - - /*global MediaStream:true */ - if (typeof MediaStream !== 'undefined') { - // override "stop" method for all browsers - if (typeof MediaStream.prototype.stop === 'undefined') { - MediaStream.prototype.stop = function() { - this.getTracks().forEach(function(track) { - track.stop(); - }); - }; - } - } - - var Storage = {}; - - if (typeof AudioContext !== 'undefined') { - Storage.AudioContext = AudioContext; - } else if (typeof webkitAudioContext !== 'undefined') { - Storage.AudioContext = webkitAudioContext; - } - - function setSrcObject(stream, element) { - if ('srcObject' in element) { - element.srcObject = stream; - } else if ('mozSrcObject' in element) { - element.mozSrcObject = stream; - } else { - element.srcObject = stream; - } - } - - this.startDrawingFrames = function() { - drawVideosToCanvas(); - }; - - function drawVideosToCanvas() { - if (isStopDrawingFrames) { - return; - } - - var videosLength = videos.length; - - var fullcanvas = false; - var remaining = []; - videos.forEach(function(video) { - if (!video.stream) { - video.stream = {}; - } - - if (video.stream.fullcanvas) { - fullcanvas = video; - } else { - // todo: video.stream.active or video.stream.live to fix blank frames issues? - remaining.push(video); - } - }); - - if (fullcanvas) { - canvas.width = fullcanvas.stream.width; - canvas.height = fullcanvas.stream.height; - } else if (remaining.length) { - canvas.width = videosLength > 1 ? remaining[0].width * 2 : remaining[0].width; - - var height = 1; - if (videosLength === 3 || videosLength === 4) { - height = 2; - } - if (videosLength === 5 || videosLength === 6) { - height = 3; - } - if (videosLength === 7 || videosLength === 8) { - height = 4; - } - if (videosLength === 9 || videosLength === 10) { - height = 5; - } - canvas.height = remaining[0].height * height; - } else { - canvas.width = self.width || 360; - canvas.height = self.height || 240; - } - - if (fullcanvas && fullcanvas instanceof HTMLVideoElement) { - drawImage(fullcanvas); - } - - remaining.forEach(function(video, idx) { - drawImage(video, idx); - }); - - setTimeout(drawVideosToCanvas, self.frameInterval); - } - - function drawImage(video, idx) { - if (isStopDrawingFrames) { - return; - } - - var x = 0; - var y = 0; - var width = video.width; - var height = video.height; - - if (idx === 1) { - x = video.width; - } - - if (idx === 2) { - y = video.height; - } - - if (idx === 3) { - x = video.width; - y = video.height; - } - - if (idx === 4) { - y = video.height * 2; - } - - if (idx === 5) { - x = video.width; - y = video.height * 2; - } - - if (idx === 6) { - y = video.height * 3; - } - - if (idx === 7) { - x = video.width; - y = video.height * 3; - } - - if (typeof video.stream.left !== 'undefined') { - x = video.stream.left; - } - - if (typeof video.stream.top !== 'undefined') { - y = video.stream.top; - } - - if (typeof video.stream.width !== 'undefined') { - width = video.stream.width; - } - - if (typeof video.stream.height !== 'undefined') { - height = video.stream.height; - } - - context.drawImage(video, x, y, width, height); - - if (typeof video.stream.onRender === 'function') { - video.stream.onRender(context, x, y, width, height, idx); - } - } - - function getMixedStream() { - isStopDrawingFrames = false; - var mixedVideoStream = getMixedVideoStream(); - - var mixedAudioStream = getMixedAudioStream(); - if (mixedAudioStream) { - mixedAudioStream.getTracks().filter(function(t) { - return t.kind === 'audio'; - }).forEach(function(track) { - mixedVideoStream.addTrack(track); - }); - } - - var fullcanvas; - arrayOfMediaStreams.forEach(function(stream) { - if (stream.fullcanvas) { - fullcanvas = true; - } - }); - - // mixedVideoStream.prototype.appendStreams = appendStreams; - // mixedVideoStream.prototype.resetVideoStreams = resetVideoStreams; - // mixedVideoStream.prototype.clearRecordedData = clearRecordedData; - - return mixedVideoStream; - } - - function getMixedVideoStream() { - resetVideoStreams(); - - var capturedStream; - - if ('captureStream' in canvas) { - capturedStream = canvas.captureStream(); - } else if ('mozCaptureStream' in canvas) { - capturedStream = canvas.mozCaptureStream(); - } else if (!self.disableLogs) { - console.error('Upgrade to latest Chrome or otherwise enable this flag: chrome://flags/#enable-experimental-web-platform-features'); - } - - var videoStream = new MediaStream(); - - capturedStream.getTracks().filter(function(t) { - return t.kind === 'video'; - }).forEach(function(track) { - videoStream.addTrack(track); - }); - - canvas.stream = videoStream; - - return videoStream; - } - - function getMixedAudioStream() { - // via: @pehrsons - if (!Storage.AudioContextConstructor) { - Storage.AudioContextConstructor = new Storage.AudioContext(); - } - - self.audioContext = Storage.AudioContextConstructor; - - self.audioSources = []; - - if (self.useGainNode === true) { - self.gainNode = self.audioContext.createGain(); - self.gainNode.connect(self.audioContext.destination); - self.gainNode.gain.value = 0; // don't hear self - } - - var audioTracksLength = 0; - arrayOfMediaStreams.forEach(function(stream) { - if (!stream.getTracks().filter(function(t) { - return t.kind === 'audio'; - }).length) { - return; - } - - audioTracksLength++; - - var audioSource = self.audioContext.createMediaStreamSource(stream); - - if (self.useGainNode === true) { - audioSource.connect(self.gainNode); - } - - self.audioSources.push(audioSource); - }); - - if (!audioTracksLength) { - // because "self.audioContext" is not initialized - // that's why we've to ignore rest of the code - return; - } - - self.audioDestination = self.audioContext.createMediaStreamDestination(); - self.audioSources.forEach(function(audioSource) { - audioSource.connect(self.audioDestination); - }); - return self.audioDestination.stream; - } - - function getVideo(stream) { - var video = document.createElement('video'); - - setSrcObject(stream, video); - - video.className = elementClass; - - video.muted = true; - video.volume = 0; - - video.width = stream.width || self.width || 360; - video.height = stream.height || self.height || 240; - - video.play(); - - return video; - } - - this.appendStreams = function(streams) { - if (!streams) { - throw 'First parameter is required.'; - } - - if (!(streams instanceof Array)) { - streams = [streams]; - } - - streams.forEach(function(stream) { - var newStream = new MediaStream(); - - if (stream.getTracks().filter(function(t) { - return t.kind === 'video'; - }).length) { - var video = getVideo(stream); - video.stream = stream; - videos.push(video); - - newStream.addTrack(stream.getTracks().filter(function(t) { - return t.kind === 'video'; - })[0]); - } - - if (stream.getTracks().filter(function(t) { - return t.kind === 'audio'; - }).length) { - var audioSource = self.audioContext.createMediaStreamSource(stream); - self.audioDestination = self.audioContext.createMediaStreamDestination(); - audioSource.connect(self.audioDestination); - - newStream.addTrack(self.audioDestination.stream.getTracks().filter(function(t) { - return t.kind === 'audio'; - })[0]); - } - - arrayOfMediaStreams.push(newStream); - }); - }; - - this.releaseStreams = function() { - videos = []; - isStopDrawingFrames = true; - - if (self.gainNode) { - self.gainNode.disconnect(); - self.gainNode = null; - } - - if (self.audioSources.length) { - self.audioSources.forEach(function(source) { - source.disconnect(); - }); - self.audioSources = []; - } - - if (self.audioDestination) { - self.audioDestination.disconnect(); - self.audioDestination = null; - } - - if (self.audioContext) { - self.audioContext.close(); - } - - self.audioContext = null; - - context.clearRect(0, 0, canvas.width, canvas.height); - - if (canvas.stream) { - canvas.stream.stop(); - canvas.stream = null; - } - }; - - this.resetVideoStreams = function(streams) { - if (streams && !(streams instanceof Array)) { - streams = [streams]; - } - - resetVideoStreams(streams); - }; - - function resetVideoStreams(streams) { - videos = []; - streams = streams || arrayOfMediaStreams; - - // via: @adrian-ber - streams.forEach(function(stream) { - if (!stream.getTracks().filter(function(t) { - return t.kind === 'video'; - }).length) { - return; - } - - var video = getVideo(stream); - video.stream = stream; - videos.push(video); - }); - } - - // for debugging - this.name = 'MultiStreamsMixer'; - this.toString = function() { - return this.name; - }; - - this.getMixedStream = getMixedStream; - -} - -if (typeof RecordRTC === 'undefined') { - if (typeof module !== 'undefined' /* && !!module.exports*/ ) { - module.exports = MultiStreamsMixer; - } - - if (typeof define === 'function' && define.amd) { - define('MultiStreamsMixer', [], function() { - return MultiStreamsMixer; - }); - } -} - -// ______________________ -// MultiStreamRecorder.js - -/* - * Video conference recording, using captureStream API along with WebAudio and Canvas2D API. - */ - -/** - * MultiStreamRecorder can record multiple videos in single container. - * @summary Multi-videos recorder. - * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} - * @author {@link https://MuazKhan.com|Muaz Khan} - * @typedef MultiStreamRecorder - * @class - * @example - * var options = { - * mimeType: 'video/webm' - * } - * var recorder = new MultiStreamRecorder(ArrayOfMediaStreams, options); - * recorder.record(); - * recorder.stop(function(blob) { - * video.src = URL.createObjectURL(blob); - * - * // or - * var blob = recorder.blob; - * }); - * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} - * @param {MediaStreams} mediaStreams - Array of MediaStreams. - * @param {object} config - {disableLogs:true, frameInterval: 1, mimeType: "video/webm"} - */ - -function MultiStreamRecorder(arrayOfMediaStreams, options) { - arrayOfMediaStreams = arrayOfMediaStreams || []; - var self = this; - - var mixer; - var mediaRecorder; - - options = options || { - elementClass: 'multi-streams-mixer', - mimeType: 'video/webm', - video: { - width: 360, - height: 240 - } - }; - - if (!options.frameInterval) { - options.frameInterval = 10; - } - - if (!options.video) { - options.video = {}; - } - - if (!options.video.width) { - options.video.width = 360; - } - - if (!options.video.height) { - options.video.height = 240; - } - - /** - * This method records all MediaStreams. - * @method - * @memberof MultiStreamRecorder - * @example - * recorder.record(); - */ - this.record = function() { - // github/muaz-khan/MultiStreamsMixer - mixer = new MultiStreamsMixer(arrayOfMediaStreams, options.elementClass || 'multi-streams-mixer'); - - if (getAllVideoTracks().length) { - mixer.frameInterval = options.frameInterval || 10; - mixer.width = options.video.width || 360; - mixer.height = options.video.height || 240; - mixer.startDrawingFrames(); - } - - if (options.previewStream && typeof options.previewStream === 'function') { - options.previewStream(mixer.getMixedStream()); - } - - // record using MediaRecorder API - mediaRecorder = new MediaStreamRecorder(mixer.getMixedStream(), options); - mediaRecorder.record(); - }; - - function getAllVideoTracks() { - var tracks = []; - arrayOfMediaStreams.forEach(function(stream) { - getTracks(stream, 'video').forEach(function(track) { - tracks.push(track); - }); - }); - return tracks; - } - - /** - * This method stops recording MediaStream. - * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee. - * @method - * @memberof MultiStreamRecorder - * @example - * recorder.stop(function(blob) { - * video.src = URL.createObjectURL(blob); - * }); - */ - this.stop = function(callback) { - if (!mediaRecorder) { - return; - } - - mediaRecorder.stop(function(blob) { - self.blob = blob; - - callback(blob); - - self.clearRecordedData(); - }); - }; - - /** - * This method pauses the recording process. - * @method - * @memberof MultiStreamRecorder - * @example - * recorder.pause(); - */ - this.pause = function() { - if (mediaRecorder) { - mediaRecorder.pause(); - } - }; - - /** - * This method resumes the recording process. - * @method - * @memberof MultiStreamRecorder - * @example - * recorder.resume(); - */ - this.resume = function() { - if (mediaRecorder) { - mediaRecorder.resume(); - } - }; - - /** - * This method resets currently recorded data. - * @method - * @memberof MultiStreamRecorder - * @example - * recorder.clearRecordedData(); - */ - this.clearRecordedData = function() { - if (mediaRecorder) { - mediaRecorder.clearRecordedData(); - mediaRecorder = null; - } - - if (mixer) { - mixer.releaseStreams(); - mixer = null; - } - }; - - /** - * Add extra media-streams to existing recordings. - * @method - * @memberof MultiStreamRecorder - * @param {MediaStreams} mediaStreams - Array of MediaStreams - * @example - * recorder.addStreams([newAudioStream, newVideoStream]); - */ - this.addStreams = function(streams) { - if (!streams) { - throw 'First parameter is required.'; - } - - if (!(streams instanceof Array)) { - streams = [streams]; - } - - arrayOfMediaStreams.concat(streams); - - if (!mediaRecorder || !mixer) { - return; - } - - mixer.appendStreams(streams); - - if (options.previewStream && typeof options.previewStream === 'function') { - options.previewStream(mixer.getMixedStream()); - } - }; - - /** - * Reset videos during live recording. Replace old videos e.g. replace cameras with full-screen. - * @method - * @memberof MultiStreamRecorder - * @param {MediaStreams} mediaStreams - Array of MediaStreams - * @example - * recorder.resetVideoStreams([newVideo1, newVideo2]); - */ - this.resetVideoStreams = function(streams) { - if (!mixer) { - return; - } - - if (streams && !(streams instanceof Array)) { - streams = [streams]; - } - - mixer.resetVideoStreams(streams); - }; - - /** - * Returns MultiStreamsMixer - * @method - * @memberof MultiStreamRecorder - * @example - * let mixer = recorder.getMixer(); - * mixer.appendStreams([newStream]); - */ - this.getMixer = function() { - return mixer; - }; - - // for debugging - this.name = 'MultiStreamRecorder'; - this.toString = function() { - return this.name; - }; -} - -if (typeof RecordRTC !== 'undefined') { - RecordRTC.MultiStreamRecorder = MultiStreamRecorder; -} - -// _____________________ -// RecordRTC.promises.js - -/** - * RecordRTCPromisesHandler adds promises support in {@link RecordRTC}. Try a {@link https://github.com/muaz-khan/RecordRTC/blob/master/simple-demos/RecordRTCPromisesHandler.html|demo here} - * @summary Promises for {@link RecordRTC} - * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} - * @author {@link https://MuazKhan.com|Muaz Khan} - * @typedef RecordRTCPromisesHandler - * @class - * @example - * var recorder = new RecordRTCPromisesHandler(mediaStream, options); - * recorder.startRecording() - * .then(successCB) - * .catch(errorCB); - * // Note: You can access all RecordRTC API using "recorder.recordRTC" e.g. - * recorder.recordRTC.onStateChanged = function(state) {}; - * recorder.recordRTC.setRecordingDuration(5000); - * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} - * @param {MediaStream} mediaStream - Single media-stream object, array of media-streams, html-canvas-element, etc. - * @param {object} config - {type:"video", recorderType: MediaStreamRecorder, disableLogs: true, numberOfAudioChannels: 1, bufferSize: 0, sampleRate: 0, video: HTMLVideoElement, etc.} - * @throws Will throw an error if "new" keyword is not used to initiate "RecordRTCPromisesHandler". Also throws error if first argument "MediaStream" is missing. - * @requires {@link RecordRTC} - */ - -function RecordRTCPromisesHandler(mediaStream, options) { - if (!this) { - throw 'Use "new RecordRTCPromisesHandler()"'; - } - - if (typeof mediaStream === 'undefined') { - throw 'First argument "MediaStream" is required.'; - } - - var self = this; - - /** - * @property {Blob} blob - Access/reach the native {@link RecordRTC} object. - * @memberof RecordRTCPromisesHandler - * @example - * let internal = recorder.recordRTC.getInternalRecorder(); - * alert(internal instanceof MediaStreamRecorder); - * recorder.recordRTC.onStateChanged = function(state) {}; - */ - self.recordRTC = new RecordRTC(mediaStream, options); - - /** - * This method records MediaStream. - * @method - * @memberof RecordRTCPromisesHandler - * @example - * recorder.startRecording() - * .then(successCB) - * .catch(errorCB); - */ - this.startRecording = function() { - return new Promise(function(resolve, reject) { - try { - self.recordRTC.startRecording(); - resolve(); - } catch (e) { - reject(e); - } - }); - }; - - /** - * This method stops the recording. - * @method - * @memberof RecordRTCPromisesHandler - * @example - * recorder.stopRecording().then(function() { - * var blob = recorder.getBlob(); - * }).catch(errorCB); - */ - this.stopRecording = function() { - return new Promise(function(resolve, reject) { - try { - self.recordRTC.stopRecording(function(url) { - self.blob = self.recordRTC.getBlob(); - - if (!self.blob || !self.blob.size) { - reject('Empty blob.', self.blob); - return; - } - - resolve(url); - }); - } catch (e) { - reject(e); - } - }); - }; - - /** - * This method pauses the recording. You can resume recording using "resumeRecording" method. - * @method - * @memberof RecordRTCPromisesHandler - * @example - * recorder.pauseRecording() - * .then(successCB) - * .catch(errorCB); - */ - this.pauseRecording = function() { - return new Promise(function(resolve, reject) { - try { - self.recordRTC.pauseRecording(); - resolve(); - } catch (e) { - reject(e); - } - }); - }; - - /** - * This method resumes the recording. - * @method - * @memberof RecordRTCPromisesHandler - * @example - * recorder.resumeRecording() - * .then(successCB) - * .catch(errorCB); - */ - this.resumeRecording = function() { - return new Promise(function(resolve, reject) { - try { - self.recordRTC.resumeRecording(); - resolve(); - } catch (e) { - reject(e); - } - }); - }; - - /** - * This method returns data-url for the recorded blob. - * @method - * @memberof RecordRTCPromisesHandler - * @example - * recorder.stopRecording().then(function() { - * recorder.getDataURL().then(function(dataURL) { - * window.open(dataURL); - * }).catch(errorCB);; - * }).catch(errorCB); - */ - this.getDataURL = function(callback) { - return new Promise(function(resolve, reject) { - try { - self.recordRTC.getDataURL(function(dataURL) { - resolve(dataURL); - }); - } catch (e) { - reject(e); - } - }); - }; - - /** - * This method returns the recorded blob. - * @method - * @memberof RecordRTCPromisesHandler - * @example - * recorder.stopRecording().then(function() { - * recorder.getBlob().then(function(blob) {}) - * }).catch(errorCB); - */ - this.getBlob = function() { - return new Promise(function(resolve, reject) { - try { - resolve(self.recordRTC.getBlob()); - } catch (e) { - reject(e); - } - }); - }; - - /** - * This method returns the internal recording object. - * @method - * @memberof RecordRTCPromisesHandler - * @example - * let internalRecorder = await recorder.getInternalRecorder(); - * if(internalRecorder instanceof MultiStreamRecorder) { - * internalRecorder.addStreams([newAudioStream]); - * internalRecorder.resetVideoStreams([screenStream]); - * } - * @returns {Object} - */ - this.getInternalRecorder = function() { - return new Promise(function(resolve, reject) { - try { - resolve(self.recordRTC.getInternalRecorder()); - } catch (e) { - reject(e); - } - }); - }; - - /** - * This method resets the recorder. So that you can reuse single recorder instance many times. - * @method - * @memberof RecordRTCPromisesHandler - * @example - * await recorder.reset(); - * recorder.startRecording(); // record again - */ - this.reset = function() { - return new Promise(function(resolve, reject) { - try { - resolve(self.recordRTC.reset()); - } catch (e) { - reject(e); - } - }); - }; - - /** - * Destroy RecordRTC instance. Clear all recorders and objects. - * @method - * @memberof RecordRTCPromisesHandler - * @example - * recorder.destroy().then(successCB).catch(errorCB); - */ - this.destroy = function() { - return new Promise(function(resolve, reject) { - try { - resolve(self.recordRTC.destroy()); - } catch (e) { - reject(e); - } - }); - }; - - /** - * Get recorder's readonly state. - * @method - * @memberof RecordRTCPromisesHandler - * @example - * let state = await recorder.getState(); - * // or - * recorder.getState().then(state => { console.log(state); }) - * @returns {String} Returns recording state. - */ - this.getState = function() { - return new Promise(function(resolve, reject) { - try { - resolve(self.recordRTC.getState()); - } catch (e) { - reject(e); - } - }); - }; - - /** - * @property {Blob} blob - Recorded data as "Blob" object. - * @memberof RecordRTCPromisesHandler - * @example - * await recorder.stopRecording(); - * let blob = recorder.getBlob(); // or "recorder.recordRTC.blob" - * invokeSaveAsDialog(blob); - */ - this.blob = null; - - /** - * RecordRTC version number - * @property {String} version - Release version number. - * @memberof RecordRTCPromisesHandler - * @static - * @readonly - * @example - * alert(recorder.version); - */ - this.version = '5.6.1'; -} - -if (typeof RecordRTC !== 'undefined') { - RecordRTC.RecordRTCPromisesHandler = RecordRTCPromisesHandler; -} - -// ______________________ -// WebAssemblyRecorder.js - -/** - * WebAssemblyRecorder lets you create webm videos in JavaScript via WebAssembly. The library consumes raw RGBA32 buffers (4 bytes per pixel) and turns them into a webm video with the given framerate and quality. This makes it compatible out-of-the-box with ImageData from a CANVAS. With realtime mode you can also use webm-wasm for streaming webm videos. - * @summary Video recording feature in Chrome, Firefox and maybe Edge. - * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} - * @author {@link https://MuazKhan.com|Muaz Khan} - * @typedef WebAssemblyRecorder - * @class - * @example - * var recorder = new WebAssemblyRecorder(mediaStream); - * recorder.record(); - * recorder.stop(function(blob) { - * video.src = URL.createObjectURL(blob); - * }); - * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} - * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API. - * @param {object} config - {webAssemblyPath:'webm-wasm.wasm',workerPath: 'webm-worker.js', frameRate: 30, width: 1920, height: 1080, bitrate: 1024, realtime: true} - */ -function WebAssemblyRecorder(stream, config) { - // based on: github.com/GoogleChromeLabs/webm-wasm - - if (typeof ReadableStream === 'undefined' || typeof WritableStream === 'undefined') { - // because it fixes readable/writable streams issues - console.error('Following polyfill is strongly recommended: https://unpkg.com/@mattiasbuelens/web-streams-polyfill/dist/polyfill.min.js'); - } - - config = config || {}; - - config.width = config.width || 640; - config.height = config.height || 480; - config.frameRate = config.frameRate || 30; - config.bitrate = config.bitrate || 1200; - config.realtime = config.realtime || true; - - function createBufferURL(buffer, type) { - return URL.createObjectURL(new Blob([buffer], { - type: type || '' - })); - } - - var finished; - - function cameraStream() { - return new ReadableStream({ - start: function(controller) { - var cvs = document.createElement('canvas'); - var video = document.createElement('video'); - var first = true; - video.srcObject = stream; - video.muted = true; - video.height = config.height; - video.width = config.width; - video.volume = 0; - video.onplaying = function() { - cvs.width = config.width; - cvs.height = config.height; - var ctx = cvs.getContext('2d'); - var frameTimeout = 1000 / config.frameRate; - var cameraTimer = setInterval(function f() { - if (finished) { - clearInterval(cameraTimer); - controller.close(); - } - - if (first) { - first = false; - if (config.onVideoProcessStarted) { - config.onVideoProcessStarted(); - } - } - - ctx.drawImage(video, 0, 0); - if (controller._controlledReadableStream.state !== 'closed') { - try { - controller.enqueue( - ctx.getImageData(0, 0, config.width, config.height) - ); - } catch (e) {} - } - }, frameTimeout); - }; - video.play(); - } - }); - } - - var worker; - - function startRecording(stream, buffer) { - if (!config.workerPath && !buffer) { - finished = false; - - // is it safe to use @latest ? - - fetch( - 'https://unpkg.com/webm-wasm@latest/dist/webm-worker.js' - ).then(function(r) { - r.arrayBuffer().then(function(buffer) { - startRecording(stream, buffer); - }); - }); - return; - } - - if (!config.workerPath && buffer instanceof ArrayBuffer) { - var blob = new Blob([buffer], { - type: 'text/javascript' - }); - config.workerPath = URL.createObjectURL(blob); - } - - if (!config.workerPath) { - console.error('workerPath parameter is missing.'); - } - - worker = new Worker(config.workerPath); - - worker.postMessage(config.webAssemblyPath || 'https://unpkg.com/webm-wasm@latest/dist/webm-wasm.wasm'); - worker.addEventListener('message', function(event) { - if (event.data === 'READY') { - worker.postMessage({ - width: config.width, - height: config.height, - bitrate: config.bitrate || 1200, - timebaseDen: config.frameRate || 30, - realtime: config.realtime - }); - - cameraStream().pipeTo(new WritableStream({ - write: function(image) { - if (finished) { - console.error('Got image, but recorder is finished!'); - return; - } - - worker.postMessage(image.data.buffer, [image.data.buffer]); - } - })); - } else if (!!event.data) { - if (!isPaused) { - arrayOfBuffers.push(event.data); - } - } - }); - } - - /** - * This method records video. - * @method - * @memberof WebAssemblyRecorder - * @example - * recorder.record(); - */ - this.record = function() { - arrayOfBuffers = []; - isPaused = false; - this.blob = null; - startRecording(stream); - - if (typeof config.initCallback === 'function') { - config.initCallback(); - } - }; - - var isPaused; - - /** - * This method pauses the recording process. - * @method - * @memberof WebAssemblyRecorder - * @example - * recorder.pause(); - */ - this.pause = function() { - isPaused = true; - }; - - /** - * This method resumes the recording process. - * @method - * @memberof WebAssemblyRecorder - * @example - * recorder.resume(); - */ - this.resume = function() { - isPaused = false; - }; - - function terminate(callback) { - if (!worker) { - if (callback) { - callback(); - } - - return; - } - - // Wait for null event data to indicate that the encoding is complete - worker.addEventListener('message', function(event) { - if (event.data === null) { - worker.terminate(); - worker = null; - - if (callback) { - callback(); - } - } - }); - - worker.postMessage(null); - } - - var arrayOfBuffers = []; - - /** - * This method stops recording video. - * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee. - * @method - * @memberof WebAssemblyRecorder - * @example - * recorder.stop(function(blob) { - * video.src = URL.createObjectURL(blob); - * }); - */ - this.stop = function(callback) { - finished = true; - - var recorder = this; - - terminate(function() { - recorder.blob = new Blob(arrayOfBuffers, { - type: 'video/webm' - }); - - callback(recorder.blob); - }); - }; - - // for debugging - this.name = 'WebAssemblyRecorder'; - this.toString = function() { - return this.name; - }; - - /** - * This method resets currently recorded data. - * @method - * @memberof WebAssemblyRecorder - * @example - * recorder.clearRecordedData(); - */ - this.clearRecordedData = function() { - arrayOfBuffers = []; - isPaused = false; - this.blob = null; - - // todo: if recording-ON then STOP it first - }; - - /** - * @property {Blob} blob - The recorded blob object. - * @memberof WebAssemblyRecorder - * @example - * recorder.stop(function(){ - * var blob = recorder.blob; - * }); - */ - this.blob = null; -} - -if (typeof RecordRTC !== 'undefined') { - RecordRTC.WebAssemblyRecorder = WebAssemblyRecorder; -} diff --git a/static/kevin-master/assets/js/adapter.js b/static/kevin-master/assets/js/adapter.js deleted file mode 100644 index 5d9dd40..0000000 --- a/static/kevin-master/assets/js/adapter.js +++ /dev/null @@ -1,5623 +0,0 @@ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.adapter = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 0 && arguments[0] !== undefined ? arguments[0] : {}, - window = _ref.window; - - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { - shimChrome: true, - shimFirefox: true, - shimEdge: true, - shimSafari: true - }; - - // Utils. - var logging = utils.log; - var browserDetails = utils.detectBrowser(window); - - var adapter = { - browserDetails: browserDetails, - commonShim: commonShim, - extractVersion: utils.extractVersion, - disableLog: utils.disableLog, - disableWarnings: utils.disableWarnings - }; - - // Shim browser if found. - switch (browserDetails.browser) { - case 'chrome': - if (!chromeShim || !chromeShim.shimPeerConnection || !options.shimChrome) { - logging('Chrome shim is not included in this adapter release.'); - return adapter; - } - if (browserDetails.version === null) { - logging('Chrome shim can not determine version, not shimming.'); - return adapter; - } - logging('adapter.js shimming chrome.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = chromeShim; - - chromeShim.shimGetUserMedia(window); - chromeShim.shimMediaStream(window); - chromeShim.shimPeerConnection(window); - chromeShim.shimOnTrack(window); - chromeShim.shimAddTrackRemoveTrack(window); - chromeShim.shimGetSendersWithDtmf(window); - chromeShim.shimGetStats(window); - chromeShim.shimSenderReceiverGetStats(window); - chromeShim.fixNegotiationNeeded(window); - - commonShim.shimRTCIceCandidate(window); - commonShim.shimConnectionState(window); - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - commonShim.removeAllowExtmapMixed(window); - break; - case 'firefox': - if (!firefoxShim || !firefoxShim.shimPeerConnection || !options.shimFirefox) { - logging('Firefox shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming firefox.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = firefoxShim; - - firefoxShim.shimGetUserMedia(window); - firefoxShim.shimPeerConnection(window); - firefoxShim.shimOnTrack(window); - firefoxShim.shimRemoveStream(window); - firefoxShim.shimSenderGetStats(window); - firefoxShim.shimReceiverGetStats(window); - firefoxShim.shimRTCDataChannel(window); - firefoxShim.shimAddTransceiver(window); - firefoxShim.shimGetParameters(window); - firefoxShim.shimCreateOffer(window); - firefoxShim.shimCreateAnswer(window); - - commonShim.shimRTCIceCandidate(window); - commonShim.shimConnectionState(window); - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - case 'edge': - if (!edgeShim || !edgeShim.shimPeerConnection || !options.shimEdge) { - logging('MS edge shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming edge.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = edgeShim; - - edgeShim.shimGetUserMedia(window); - edgeShim.shimGetDisplayMedia(window); - edgeShim.shimPeerConnection(window); - edgeShim.shimReplaceTrack(window); - - // the edge shim implements the full RTCIceCandidate object. - - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - case 'safari': - if (!safariShim || !options.shimSafari) { - logging('Safari shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming safari.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = safariShim; - - safariShim.shimRTCIceServerUrls(window); - safariShim.shimCreateOfferLegacy(window); - safariShim.shimCallbacksAPI(window); - safariShim.shimLocalStreamsAPI(window); - safariShim.shimRemoteStreamsAPI(window); - safariShim.shimTrackEventTransceiver(window); - safariShim.shimGetUserMedia(window); - safariShim.shimAudioContext(window); - - commonShim.shimRTCIceCandidate(window); - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - commonShim.removeAllowExtmapMixed(window); - break; - default: - logging('Unsupported browser!'); - break; - } - - return adapter; -} - -// Browser shims. - -},{"./chrome/chrome_shim":3,"./common_shim":6,"./edge/edge_shim":7,"./firefox/firefox_shim":11,"./safari/safari_shim":14,"./utils":15}],3:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ -/* eslint-env node */ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined; - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - -var _getusermedia = require('./getusermedia'); - -Object.defineProperty(exports, 'shimGetUserMedia', { - enumerable: true, - get: function get() { - return _getusermedia.shimGetUserMedia; - } -}); - -var _getdisplaymedia = require('./getdisplaymedia'); - -Object.defineProperty(exports, 'shimGetDisplayMedia', { - enumerable: true, - get: function get() { - return _getdisplaymedia.shimGetDisplayMedia; - } -}); -exports.shimMediaStream = shimMediaStream; -exports.shimOnTrack = shimOnTrack; -exports.shimGetSendersWithDtmf = shimGetSendersWithDtmf; -exports.shimGetStats = shimGetStats; -exports.shimSenderReceiverGetStats = shimSenderReceiverGetStats; -exports.shimAddTrackRemoveTrackWithNative = shimAddTrackRemoveTrackWithNative; -exports.shimAddTrackRemoveTrack = shimAddTrackRemoveTrack; -exports.shimPeerConnection = shimPeerConnection; -exports.fixNegotiationNeeded = fixNegotiationNeeded; - -var _utils = require('../utils.js'); - -var utils = _interopRequireWildcard(_utils); - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - -function shimMediaStream(window) { - window.MediaStream = window.MediaStream || window.webkitMediaStream; -} - -function shimOnTrack(window) { - if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && !('ontrack' in window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { - get: function get() { - return this._ontrack; - }, - set: function set(f) { - if (this._ontrack) { - this.removeEventListener('track', this._ontrack); - } - this.addEventListener('track', this._ontrack = f); - }, - - enumerable: true, - configurable: true - }); - var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; - window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() { - var _this = this; - - if (!this._ontrackpoly) { - this._ontrackpoly = function (e) { - // onaddstream does not fire when a track is added to an existing - // stream. But stream.onaddtrack is implemented so we use that. - e.stream.addEventListener('addtrack', function (te) { - var receiver = void 0; - if (window.RTCPeerConnection.prototype.getReceivers) { - receiver = _this.getReceivers().find(function (r) { - return r.track && r.track.id === te.track.id; - }); - } else { - receiver = { track: te.track }; - } - - var event = new Event('track'); - event.track = te.track; - event.receiver = receiver; - event.transceiver = { receiver: receiver }; - event.streams = [e.stream]; - _this.dispatchEvent(event); - }); - e.stream.getTracks().forEach(function (track) { - var receiver = void 0; - if (window.RTCPeerConnection.prototype.getReceivers) { - receiver = _this.getReceivers().find(function (r) { - return r.track && r.track.id === track.id; - }); - } else { - receiver = { track: track }; - } - var event = new Event('track'); - event.track = track; - event.receiver = receiver; - event.transceiver = { receiver: receiver }; - event.streams = [e.stream]; - _this.dispatchEvent(event); - }); - }; - this.addEventListener('addstream', this._ontrackpoly); - } - return origSetRemoteDescription.apply(this, arguments); - }; - } else { - // even if RTCRtpTransceiver is in window, it is only used and - // emitted in unified-plan. Unfortunately this means we need - // to unconditionally wrap the event. - utils.wrapPeerConnectionEvent(window, 'track', function (e) { - if (!e.transceiver) { - Object.defineProperty(e, 'transceiver', { value: { receiver: e.receiver } }); - } - return e; - }); - } -} - -function shimGetSendersWithDtmf(window) { - // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack. - if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && !('getSenders' in window.RTCPeerConnection.prototype) && 'createDTMFSender' in window.RTCPeerConnection.prototype) { - var shimSenderWithDtmf = function shimSenderWithDtmf(pc, track) { - return { - track: track, - get dtmf() { - if (this._dtmf === undefined) { - if (track.kind === 'audio') { - this._dtmf = pc.createDTMFSender(track); - } else { - this._dtmf = null; - } - } - return this._dtmf; - }, - _pc: pc - }; - }; - - // augment addTrack when getSenders is not available. - if (!window.RTCPeerConnection.prototype.getSenders) { - window.RTCPeerConnection.prototype.getSenders = function getSenders() { - this._senders = this._senders || []; - return this._senders.slice(); // return a copy of the internal state. - }; - var origAddTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) { - var sender = origAddTrack.apply(this, arguments); - if (!sender) { - sender = shimSenderWithDtmf(this, track); - this._senders.push(sender); - } - return sender; - }; - - var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; - window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) { - origRemoveTrack.apply(this, arguments); - var idx = this._senders.indexOf(sender); - if (idx !== -1) { - this._senders.splice(idx, 1); - } - }; - } - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function addStream(stream) { - var _this2 = this; - - this._senders = this._senders || []; - origAddStream.apply(this, [stream]); - stream.getTracks().forEach(function (track) { - _this2._senders.push(shimSenderWithDtmf(_this2, track)); - }); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { - var _this3 = this; - - this._senders = this._senders || []; - origRemoveStream.apply(this, [stream]); - - stream.getTracks().forEach(function (track) { - var sender = _this3._senders.find(function (s) { - return s.track === track; - }); - if (sender) { - // remove sender - _this3._senders.splice(_this3._senders.indexOf(sender), 1); - } - }); - }; - } else if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && 'getSenders' in window.RTCPeerConnection.prototype && 'createDTMFSender' in window.RTCPeerConnection.prototype && window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { - var origGetSenders = window.RTCPeerConnection.prototype.getSenders; - window.RTCPeerConnection.prototype.getSenders = function getSenders() { - var _this4 = this; - - var senders = origGetSenders.apply(this, []); - senders.forEach(function (sender) { - return sender._pc = _this4; - }); - return senders; - }; - - Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { - get: function get() { - if (this._dtmf === undefined) { - if (this.track.kind === 'audio') { - this._dtmf = this._pc.createDTMFSender(this.track); - } else { - this._dtmf = null; - } - } - return this._dtmf; - } - }); - } -} - -function shimGetStats(window) { - if (!window.RTCPeerConnection) { - return; - } - - var origGetStats = window.RTCPeerConnection.prototype.getStats; - window.RTCPeerConnection.prototype.getStats = function getStats() { - var _this5 = this; - - var _arguments = Array.prototype.slice.call(arguments), - selector = _arguments[0], - onSucc = _arguments[1], - onErr = _arguments[2]; - - // If selector is a function then we are in the old style stats so just - // pass back the original getStats format to avoid breaking old users. - - - if (arguments.length > 0 && typeof selector === 'function') { - return origGetStats.apply(this, arguments); - } - - // When spec-style getStats is supported, return those when called with - // either no arguments or the selector argument is null. - if (origGetStats.length === 0 && (arguments.length === 0 || typeof selector !== 'function')) { - return origGetStats.apply(this, []); - } - - var fixChromeStats_ = function fixChromeStats_(response) { - var standardReport = {}; - var reports = response.result(); - reports.forEach(function (report) { - var standardStats = { - id: report.id, - timestamp: report.timestamp, - type: { - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }[report.type] || report.type - }; - report.names().forEach(function (name) { - standardStats[name] = report.stat(name); - }); - standardReport[standardStats.id] = standardStats; - }); - - return standardReport; - }; - - // shim getStats with maplike support - var makeMapStats = function makeMapStats(stats) { - return new Map(Object.keys(stats).map(function (key) { - return [key, stats[key]]; - })); - }; - - if (arguments.length >= 2) { - var successCallbackWrapper_ = function successCallbackWrapper_(response) { - onSucc(makeMapStats(fixChromeStats_(response))); - }; - - return origGetStats.apply(this, [successCallbackWrapper_, selector]); - } - - // promise-support - return new Promise(function (resolve, reject) { - origGetStats.apply(_this5, [function (response) { - resolve(makeMapStats(fixChromeStats_(response))); - }, reject]); - }).then(onSucc, onErr); - }; -} - -function shimSenderReceiverGetStats(window) { - if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && window.RTCRtpSender && window.RTCRtpReceiver)) { - return; - } - - // shim sender stats. - if (!('getStats' in window.RTCRtpSender.prototype)) { - var origGetSenders = window.RTCPeerConnection.prototype.getSenders; - if (origGetSenders) { - window.RTCPeerConnection.prototype.getSenders = function getSenders() { - var _this6 = this; - - var senders = origGetSenders.apply(this, []); - senders.forEach(function (sender) { - return sender._pc = _this6; - }); - return senders; - }; - } - - var origAddTrack = window.RTCPeerConnection.prototype.addTrack; - if (origAddTrack) { - window.RTCPeerConnection.prototype.addTrack = function addTrack() { - var sender = origAddTrack.apply(this, arguments); - sender._pc = this; - return sender; - }; - } - window.RTCRtpSender.prototype.getStats = function getStats() { - var sender = this; - return this._pc.getStats().then(function (result) { - return ( - /* Note: this will include stats of all senders that - * send a track with the same id as sender.track as - * it is not possible to identify the RTCRtpSender. - */ - utils.filterStats(result, sender.track, true) - ); - }); - }; - } - - // shim receiver stats. - if (!('getStats' in window.RTCRtpReceiver.prototype)) { - var origGetReceivers = window.RTCPeerConnection.prototype.getReceivers; - if (origGetReceivers) { - window.RTCPeerConnection.prototype.getReceivers = function getReceivers() { - var _this7 = this; - - var receivers = origGetReceivers.apply(this, []); - receivers.forEach(function (receiver) { - return receiver._pc = _this7; - }); - return receivers; - }; - } - utils.wrapPeerConnectionEvent(window, 'track', function (e) { - e.receiver._pc = e.srcElement; - return e; - }); - window.RTCRtpReceiver.prototype.getStats = function getStats() { - var receiver = this; - return this._pc.getStats().then(function (result) { - return utils.filterStats(result, receiver.track, false); - }); - }; - } - - if (!('getStats' in window.RTCRtpSender.prototype && 'getStats' in window.RTCRtpReceiver.prototype)) { - return; - } - - // shim RTCPeerConnection.getStats(track). - var origGetStats = window.RTCPeerConnection.prototype.getStats; - window.RTCPeerConnection.prototype.getStats = function getStats() { - if (arguments.length > 0 && arguments[0] instanceof window.MediaStreamTrack) { - var track = arguments[0]; - var sender = void 0; - var receiver = void 0; - var err = void 0; - this.getSenders().forEach(function (s) { - if (s.track === track) { - if (sender) { - err = true; - } else { - sender = s; - } - } - }); - this.getReceivers().forEach(function (r) { - if (r.track === track) { - if (receiver) { - err = true; - } else { - receiver = r; - } - } - return r.track === track; - }); - if (err || sender && receiver) { - return Promise.reject(new DOMException('There are more than one sender or receiver for the track.', 'InvalidAccessError')); - } else if (sender) { - return sender.getStats(); - } else if (receiver) { - return receiver.getStats(); - } - return Promise.reject(new DOMException('There is no sender or receiver for the track.', 'InvalidAccessError')); - } - return origGetStats.apply(this, arguments); - }; -} - -function shimAddTrackRemoveTrackWithNative(window) { - // shim addTrack/removeTrack with native variants in order to make - // the interactions with legacy getLocalStreams behave as in other browsers. - // Keeps a mapping stream.id => [stream, rtpsenders...] - window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() { - var _this8 = this; - - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - return Object.keys(this._shimmedLocalStreams).map(function (streamId) { - return _this8._shimmedLocalStreams[streamId][0]; - }); - }; - - var origAddTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) { - if (!stream) { - return origAddTrack.apply(this, arguments); - } - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - - var sender = origAddTrack.apply(this, arguments); - if (!this._shimmedLocalStreams[stream.id]) { - this._shimmedLocalStreams[stream.id] = [stream, sender]; - } else if (this._shimmedLocalStreams[stream.id].indexOf(sender) === -1) { - this._shimmedLocalStreams[stream.id].push(sender); - } - return sender; - }; - - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function addStream(stream) { - var _this9 = this; - - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - - stream.getTracks().forEach(function (track) { - var alreadyExists = _this9.getSenders().find(function (s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', 'InvalidAccessError'); - } - }); - var existingSenders = this.getSenders(); - origAddStream.apply(this, arguments); - var newSenders = this.getSenders().filter(function (newSender) { - return existingSenders.indexOf(newSender) === -1; - }); - this._shimmedLocalStreams[stream.id] = [stream].concat(newSenders); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - delete this._shimmedLocalStreams[stream.id]; - return origRemoveStream.apply(this, arguments); - }; - - var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; - window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) { - var _this10 = this; - - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - if (sender) { - Object.keys(this._shimmedLocalStreams).forEach(function (streamId) { - var idx = _this10._shimmedLocalStreams[streamId].indexOf(sender); - if (idx !== -1) { - _this10._shimmedLocalStreams[streamId].splice(idx, 1); - } - if (_this10._shimmedLocalStreams[streamId].length === 1) { - delete _this10._shimmedLocalStreams[streamId]; - } - }); - } - return origRemoveTrack.apply(this, arguments); - }; -} - -function shimAddTrackRemoveTrack(window) { - if (!window.RTCPeerConnection) { - return; - } - var browserDetails = utils.detectBrowser(window); - // shim addTrack and removeTrack. - if (window.RTCPeerConnection.prototype.addTrack && browserDetails.version >= 65) { - return shimAddTrackRemoveTrackWithNative(window); - } - - // also shim pc.getLocalStreams when addTrack is shimmed - // to return the original streams. - var origGetLocalStreams = window.RTCPeerConnection.prototype.getLocalStreams; - window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() { - var _this11 = this; - - var nativeStreams = origGetLocalStreams.apply(this); - this._reverseStreams = this._reverseStreams || {}; - return nativeStreams.map(function (stream) { - return _this11._reverseStreams[stream.id]; - }); - }; - - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function addStream(stream) { - var _this12 = this; - - this._streams = this._streams || {}; - this._reverseStreams = this._reverseStreams || {}; - - stream.getTracks().forEach(function (track) { - var alreadyExists = _this12.getSenders().find(function (s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', 'InvalidAccessError'); - } - }); - // Add identity mapping for consistency with addTrack. - // Unless this is being used with a stream from addTrack. - if (!this._reverseStreams[stream.id]) { - var newStream = new window.MediaStream(stream.getTracks()); - this._streams[stream.id] = newStream; - this._reverseStreams[newStream.id] = stream; - stream = newStream; - } - origAddStream.apply(this, [stream]); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { - this._streams = this._streams || {}; - this._reverseStreams = this._reverseStreams || {}; - - origRemoveStream.apply(this, [this._streams[stream.id] || stream]); - delete this._reverseStreams[this._streams[stream.id] ? this._streams[stream.id].id : stream.id]; - delete this._streams[stream.id]; - }; - - window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) { - var _this13 = this; - - if (this.signalingState === 'closed') { - throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.', 'InvalidStateError'); - } - var streams = [].slice.call(arguments, 1); - if (streams.length !== 1 || !streams[0].getTracks().find(function (t) { - return t === track; - })) { - // this is not fully correct but all we can manage without - // [[associated MediaStreams]] internal slot. - throw new DOMException('The adapter.js addTrack polyfill only supports a single ' + ' stream which is associated with the specified track.', 'NotSupportedError'); - } - - var alreadyExists = this.getSenders().find(function (s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', 'InvalidAccessError'); - } - - this._streams = this._streams || {}; - this._reverseStreams = this._reverseStreams || {}; - var oldStream = this._streams[stream.id]; - if (oldStream) { - // this is using odd Chrome behaviour, use with caution: - // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815 - // Note: we rely on the high-level addTrack/dtmf shim to - // create the sender with a dtmf sender. - oldStream.addTrack(track); - - // Trigger ONN async. - Promise.resolve().then(function () { - _this13.dispatchEvent(new Event('negotiationneeded')); - }); - } else { - var newStream = new window.MediaStream([track]); - this._streams[stream.id] = newStream; - this._reverseStreams[newStream.id] = stream; - this.addStream(newStream); - } - return this.getSenders().find(function (s) { - return s.track === track; - }); - }; - - // replace the internal stream id with the external one and - // vice versa. - function replaceInternalStreamId(pc, description) { - var sdp = description.sdp; - Object.keys(pc._reverseStreams || []).forEach(function (internalId) { - var externalStream = pc._reverseStreams[internalId]; - var internalStream = pc._streams[externalStream.id]; - sdp = sdp.replace(new RegExp(internalStream.id, 'g'), externalStream.id); - }); - return new RTCSessionDescription({ - type: description.type, - sdp: sdp - }); - } - function replaceExternalStreamId(pc, description) { - var sdp = description.sdp; - Object.keys(pc._reverseStreams || []).forEach(function (internalId) { - var externalStream = pc._reverseStreams[internalId]; - var internalStream = pc._streams[externalStream.id]; - sdp = sdp.replace(new RegExp(externalStream.id, 'g'), internalStream.id); - }); - return new RTCSessionDescription({ - type: description.type, - sdp: sdp - }); - } - ['createOffer', 'createAnswer'].forEach(function (method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - var methodObj = _defineProperty({}, method, function () { - var _this14 = this; - - var args = arguments; - var isLegacyCall = arguments.length && typeof arguments[0] === 'function'; - if (isLegacyCall) { - return nativeMethod.apply(this, [function (description) { - var desc = replaceInternalStreamId(_this14, description); - args[0].apply(null, [desc]); - }, function (err) { - if (args[1]) { - args[1].apply(null, err); - } - }, arguments[2]]); - } - return nativeMethod.apply(this, arguments).then(function (description) { - return replaceInternalStreamId(_this14, description); - }); - }); - window.RTCPeerConnection.prototype[method] = methodObj[method]; - }); - - var origSetLocalDescription = window.RTCPeerConnection.prototype.setLocalDescription; - window.RTCPeerConnection.prototype.setLocalDescription = function setLocalDescription() { - if (!arguments.length || !arguments[0].type) { - return origSetLocalDescription.apply(this, arguments); - } - arguments[0] = replaceExternalStreamId(this, arguments[0]); - return origSetLocalDescription.apply(this, arguments); - }; - - // TODO: mangle getStats: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamstats-streamidentifier - - var origLocalDescription = Object.getOwnPropertyDescriptor(window.RTCPeerConnection.prototype, 'localDescription'); - Object.defineProperty(window.RTCPeerConnection.prototype, 'localDescription', { - get: function get() { - var description = origLocalDescription.get.apply(this); - if (description.type === '') { - return description; - } - return replaceInternalStreamId(this, description); - } - }); - - window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) { - var _this15 = this; - - if (this.signalingState === 'closed') { - throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.', 'InvalidStateError'); - } - // We can not yet check for sender instanceof RTCRtpSender - // since we shim RTPSender. So we check if sender._pc is set. - if (!sender._pc) { - throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack ' + 'does not implement interface RTCRtpSender.', 'TypeError'); - } - var isLocal = sender._pc === this; - if (!isLocal) { - throw new DOMException('Sender was not created by this connection.', 'InvalidAccessError'); - } - - // Search for the native stream the senders track belongs to. - this._streams = this._streams || {}; - var stream = void 0; - Object.keys(this._streams).forEach(function (streamid) { - var hasTrack = _this15._streams[streamid].getTracks().find(function (track) { - return sender.track === track; - }); - if (hasTrack) { - stream = _this15._streams[streamid]; - } - }); - - if (stream) { - if (stream.getTracks().length === 1) { - // if this is the last track of the stream, remove the stream. This - // takes care of any shimmed _senders. - this.removeStream(this._reverseStreams[stream.id]); - } else { - // relying on the same odd chrome behaviour as above. - stream.removeTrack(sender.track); - } - this.dispatchEvent(new Event('negotiationneeded')); - } - }; -} - -function shimPeerConnection(window) { - var browserDetails = utils.detectBrowser(window); - - if (!window.RTCPeerConnection && window.webkitRTCPeerConnection) { - // very basic support for old versions. - window.RTCPeerConnection = window.webkitRTCPeerConnection; - } - if (!window.RTCPeerConnection) { - return; - } - - var addIceCandidateNullSupported = window.RTCPeerConnection.prototype.addIceCandidate.length === 0; - - // shim implicit creation of RTCSessionDescription/RTCIceCandidate - if (browserDetails.version < 53) { - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'].forEach(function (method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - var methodObj = _defineProperty({}, method, function () { - arguments[0] = new (method === 'addIceCandidate' ? window.RTCIceCandidate : window.RTCSessionDescription)(arguments[0]); - return nativeMethod.apply(this, arguments); - }); - window.RTCPeerConnection.prototype[method] = methodObj[method]; - }); - } - - // support for addIceCandidate(null or undefined) - var nativeAddIceCandidate = window.RTCPeerConnection.prototype.addIceCandidate; - window.RTCPeerConnection.prototype.addIceCandidate = function addIceCandidate() { - if (!addIceCandidateNullSupported && !arguments[0]) { - if (arguments[1]) { - arguments[1].apply(null); - } - return Promise.resolve(); - } - // Firefox 68+ emits and processes {candidate: "", ...}, ignore - // in older versions. Native support planned for Chrome M77. - if (browserDetails.version < 78 && arguments[0] && arguments[0].candidate === '') { - return Promise.resolve(); - } - return nativeAddIceCandidate.apply(this, arguments); - }; -} - -// Attempt to fix ONN in plan-b mode. -function fixNegotiationNeeded(window) { - var browserDetails = utils.detectBrowser(window); - utils.wrapPeerConnectionEvent(window, 'negotiationneeded', function (e) { - var pc = e.target; - if (browserDetails.version < 72 || pc.getConfiguration && pc.getConfiguration().sdpSemantics === 'plan-b') { - if (pc.signalingState !== 'stable') { - return; - } - } - return e; - }); -} - -},{"../utils.js":15,"./getdisplaymedia":4,"./getusermedia":5}],4:[function(require,module,exports){ -/* - * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ -/* eslint-env node */ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.shimGetDisplayMedia = shimGetDisplayMedia; -function shimGetDisplayMedia(window, getSourceId) { - if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) { - return; - } - if (!window.navigator.mediaDevices) { - return; - } - // getSourceId is a function that returns a promise resolving with - // the sourceId of the screen/window/tab to be shared. - if (typeof getSourceId !== 'function') { - console.error('shimGetDisplayMedia: getSourceId argument is not ' + 'a function'); - return; - } - window.navigator.mediaDevices.getDisplayMedia = function getDisplayMedia(constraints) { - return getSourceId(constraints).then(function (sourceId) { - var widthSpecified = constraints.video && constraints.video.width; - var heightSpecified = constraints.video && constraints.video.height; - var frameRateSpecified = constraints.video && constraints.video.frameRate; - constraints.video = { - mandatory: { - chromeMediaSource: 'desktop', - chromeMediaSourceId: sourceId, - maxFrameRate: frameRateSpecified || 3 - } - }; - if (widthSpecified) { - constraints.video.mandatory.maxWidth = widthSpecified; - } - if (heightSpecified) { - constraints.video.mandatory.maxHeight = heightSpecified; - } - return window.navigator.mediaDevices.getUserMedia(constraints); - }); - }; -} - -},{}],5:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ -/* eslint-env node */ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - -exports.shimGetUserMedia = shimGetUserMedia; - -var _utils = require('../utils.js'); - -var utils = _interopRequireWildcard(_utils); - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -var logging = utils.log; - -function shimGetUserMedia(window) { - var navigator = window && window.navigator; - - if (!navigator.mediaDevices) { - return; - } - - var browserDetails = utils.detectBrowser(window); - - var constraintsToChrome_ = function constraintsToChrome_(c) { - if ((typeof c === 'undefined' ? 'undefined' : _typeof(c)) !== 'object' || c.mandatory || c.optional) { - return c; - } - var cc = {}; - Object.keys(c).forEach(function (key) { - if (key === 'require' || key === 'advanced' || key === 'mediaSource') { - return; - } - var r = _typeof(c[key]) === 'object' ? c[key] : { ideal: c[key] }; - if (r.exact !== undefined && typeof r.exact === 'number') { - r.min = r.max = r.exact; - } - var oldname_ = function oldname_(prefix, name) { - if (prefix) { - return prefix + name.charAt(0).toUpperCase() + name.slice(1); - } - return name === 'deviceId' ? 'sourceId' : name; - }; - if (r.ideal !== undefined) { - cc.optional = cc.optional || []; - var oc = {}; - if (typeof r.ideal === 'number') { - oc[oldname_('min', key)] = r.ideal; - cc.optional.push(oc); - oc = {}; - oc[oldname_('max', key)] = r.ideal; - cc.optional.push(oc); - } else { - oc[oldname_('', key)] = r.ideal; - cc.optional.push(oc); - } - } - if (r.exact !== undefined && typeof r.exact !== 'number') { - cc.mandatory = cc.mandatory || {}; - cc.mandatory[oldname_('', key)] = r.exact; - } else { - ['min', 'max'].forEach(function (mix) { - if (r[mix] !== undefined) { - cc.mandatory = cc.mandatory || {}; - cc.mandatory[oldname_(mix, key)] = r[mix]; - } - }); - } - }); - if (c.advanced) { - cc.optional = (cc.optional || []).concat(c.advanced); - } - return cc; - }; - - var shimConstraints_ = function shimConstraints_(constraints, func) { - if (browserDetails.version >= 61) { - return func(constraints); - } - constraints = JSON.parse(JSON.stringify(constraints)); - if (constraints && _typeof(constraints.audio) === 'object') { - var remap = function remap(obj, a, b) { - if (a in obj && !(b in obj)) { - obj[b] = obj[a]; - delete obj[a]; - } - }; - constraints = JSON.parse(JSON.stringify(constraints)); - remap(constraints.audio, 'autoGainControl', 'googAutoGainControl'); - remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression'); - constraints.audio = constraintsToChrome_(constraints.audio); - } - if (constraints && _typeof(constraints.video) === 'object') { - // Shim facingMode for mobile & surface pro. - var face = constraints.video.facingMode; - face = face && ((typeof face === 'undefined' ? 'undefined' : _typeof(face)) === 'object' ? face : { ideal: face }); - var getSupportedFacingModeLies = browserDetails.version < 66; - - if (face && (face.exact === 'user' || face.exact === 'environment' || face.ideal === 'user' || face.ideal === 'environment') && !(navigator.mediaDevices.getSupportedConstraints && navigator.mediaDevices.getSupportedConstraints().facingMode && !getSupportedFacingModeLies)) { - delete constraints.video.facingMode; - var matches = void 0; - if (face.exact === 'environment' || face.ideal === 'environment') { - matches = ['back', 'rear']; - } else if (face.exact === 'user' || face.ideal === 'user') { - matches = ['front']; - } - if (matches) { - // Look for matches in label, or use last cam for back (typical). - return navigator.mediaDevices.enumerateDevices().then(function (devices) { - devices = devices.filter(function (d) { - return d.kind === 'videoinput'; - }); - var dev = devices.find(function (d) { - return matches.some(function (match) { - return d.label.toLowerCase().includes(match); - }); - }); - if (!dev && devices.length && matches.includes('back')) { - dev = devices[devices.length - 1]; // more likely the back cam - } - if (dev) { - constraints.video.deviceId = face.exact ? { exact: dev.deviceId } : { ideal: dev.deviceId }; - } - constraints.video = constraintsToChrome_(constraints.video); - logging('chrome: ' + JSON.stringify(constraints)); - return func(constraints); - }); - } - } - constraints.video = constraintsToChrome_(constraints.video); - } - logging('chrome: ' + JSON.stringify(constraints)); - return func(constraints); - }; - - var shimError_ = function shimError_(e) { - if (browserDetails.version >= 64) { - return e; - } - return { - name: { - PermissionDeniedError: 'NotAllowedError', - PermissionDismissedError: 'NotAllowedError', - InvalidStateError: 'NotAllowedError', - DevicesNotFoundError: 'NotFoundError', - ConstraintNotSatisfiedError: 'OverconstrainedError', - TrackStartError: 'NotReadableError', - MediaDeviceFailedDueToShutdown: 'NotAllowedError', - MediaDeviceKillSwitchOn: 'NotAllowedError', - TabCaptureError: 'AbortError', - ScreenCaptureError: 'AbortError', - DeviceCaptureError: 'AbortError' - }[e.name] || e.name, - message: e.message, - constraint: e.constraint || e.constraintName, - toString: function toString() { - return this.name + (this.message && ': ') + this.message; - } - }; - }; - - var getUserMedia_ = function getUserMedia_(constraints, onSuccess, onError) { - shimConstraints_(constraints, function (c) { - navigator.webkitGetUserMedia(c, onSuccess, function (e) { - if (onError) { - onError(shimError_(e)); - } - }); - }); - }; - navigator.getUserMedia = getUserMedia_.bind(navigator); - - // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia - // function which returns a Promise, it does not accept spec-style - // constraints. - if (navigator.mediaDevices.getUserMedia) { - var origGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function (cs) { - return shimConstraints_(cs, function (c) { - return origGetUserMedia(c).then(function (stream) { - if (c.audio && !stream.getAudioTracks().length || c.video && !stream.getVideoTracks().length) { - stream.getTracks().forEach(function (track) { - track.stop(); - }); - throw new DOMException('', 'NotFoundError'); - } - return stream; - }, function (e) { - return Promise.reject(shimError_(e)); - }); - }); - }; - } -} - -},{"../utils.js":15}],6:[function(require,module,exports){ -/* - * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ -/* eslint-env node */ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - -exports.shimRTCIceCandidate = shimRTCIceCandidate; -exports.shimMaxMessageSize = shimMaxMessageSize; -exports.shimSendThrowTypeError = shimSendThrowTypeError; -exports.shimConnectionState = shimConnectionState; -exports.removeAllowExtmapMixed = removeAllowExtmapMixed; - -var _sdp = require('sdp'); - -var _sdp2 = _interopRequireDefault(_sdp); - -var _utils = require('./utils'); - -var utils = _interopRequireWildcard(_utils); - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function shimRTCIceCandidate(window) { - // foundation is arbitrarily chosen as an indicator for full support for - // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface - if (!window.RTCIceCandidate || window.RTCIceCandidate && 'foundation' in window.RTCIceCandidate.prototype) { - return; - } - - var NativeRTCIceCandidate = window.RTCIceCandidate; - window.RTCIceCandidate = function RTCIceCandidate(args) { - // Remove the a= which shouldn't be part of the candidate string. - if ((typeof args === 'undefined' ? 'undefined' : _typeof(args)) === 'object' && args.candidate && args.candidate.indexOf('a=') === 0) { - args = JSON.parse(JSON.stringify(args)); - args.candidate = args.candidate.substr(2); - } - - if (args.candidate && args.candidate.length) { - // Augment the native candidate with the parsed fields. - var nativeCandidate = new NativeRTCIceCandidate(args); - var parsedCandidate = _sdp2.default.parseCandidate(args.candidate); - var augmentedCandidate = Object.assign(nativeCandidate, parsedCandidate); - - // Add a serializer that does not serialize the extra attributes. - augmentedCandidate.toJSON = function toJSON() { - return { - candidate: augmentedCandidate.candidate, - sdpMid: augmentedCandidate.sdpMid, - sdpMLineIndex: augmentedCandidate.sdpMLineIndex, - usernameFragment: augmentedCandidate.usernameFragment - }; - }; - return augmentedCandidate; - } - return new NativeRTCIceCandidate(args); - }; - window.RTCIceCandidate.prototype = NativeRTCIceCandidate.prototype; - - // Hook up the augmented candidate in onicecandidate and - // addEventListener('icecandidate', ...) - utils.wrapPeerConnectionEvent(window, 'icecandidate', function (e) { - if (e.candidate) { - Object.defineProperty(e, 'candidate', { - value: new window.RTCIceCandidate(e.candidate), - writable: 'false' - }); - } - return e; - }); -} - -function shimMaxMessageSize(window) { - if (!window.RTCPeerConnection) { - return; - } - var browserDetails = utils.detectBrowser(window); - - if (!('sctp' in window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'sctp', { - get: function get() { - return typeof this._sctp === 'undefined' ? null : this._sctp; - } - }); - } - - var sctpInDescription = function sctpInDescription(description) { - if (!description || !description.sdp) { - return false; - } - var sections = _sdp2.default.splitSections(description.sdp); - sections.shift(); - return sections.some(function (mediaSection) { - var mLine = _sdp2.default.parseMLine(mediaSection); - return mLine && mLine.kind === 'application' && mLine.protocol.indexOf('SCTP') !== -1; - }); - }; - - var getRemoteFirefoxVersion = function getRemoteFirefoxVersion(description) { - // TODO: Is there a better solution for detecting Firefox? - var match = description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/); - if (match === null || match.length < 2) { - return -1; - } - var version = parseInt(match[1], 10); - // Test for NaN (yes, this is ugly) - return version !== version ? -1 : version; - }; - - var getCanSendMaxMessageSize = function getCanSendMaxMessageSize(remoteIsFirefox) { - // Every implementation we know can send at least 64 KiB. - // Note: Although Chrome is technically able to send up to 256 KiB, the - // data does not reach the other peer reliably. - // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=8419 - var canSendMaxMessageSize = 65536; - if (browserDetails.browser === 'firefox') { - if (browserDetails.version < 57) { - if (remoteIsFirefox === -1) { - // FF < 57 will send in 16 KiB chunks using the deprecated PPID - // fragmentation. - canSendMaxMessageSize = 16384; - } else { - // However, other FF (and RAWRTC) can reassemble PPID-fragmented - // messages. Thus, supporting ~2 GiB when sending. - canSendMaxMessageSize = 2147483637; - } - } else if (browserDetails.version < 60) { - // Currently, all FF >= 57 will reset the remote maximum message size - // to the default value when a data channel is created at a later - // stage. :( - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 - canSendMaxMessageSize = browserDetails.version === 57 ? 65535 : 65536; - } else { - // FF >= 60 supports sending ~2 GiB - canSendMaxMessageSize = 2147483637; - } - } - return canSendMaxMessageSize; - }; - - var getMaxMessageSize = function getMaxMessageSize(description, remoteIsFirefox) { - // Note: 65536 bytes is the default value from the SDP spec. Also, - // every implementation we know supports receiving 65536 bytes. - var maxMessageSize = 65536; - - // FF 57 has a slightly incorrect default remote max message size, so - // we need to adjust it here to avoid a failure when sending. - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1425697 - if (browserDetails.browser === 'firefox' && browserDetails.version === 57) { - maxMessageSize = 65535; - } - - var match = _sdp2.default.matchPrefix(description.sdp, 'a=max-message-size:'); - if (match.length > 0) { - maxMessageSize = parseInt(match[0].substr(19), 10); - } else if (browserDetails.browser === 'firefox' && remoteIsFirefox !== -1) { - // If the maximum message size is not present in the remote SDP and - // both local and remote are Firefox, the remote peer can receive - // ~2 GiB. - maxMessageSize = 2147483637; - } - return maxMessageSize; - }; - - var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; - window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() { - this._sctp = null; - // Chrome decided to not expose .sctp in plan-b mode. - // As usual, adapter.js has to do an 'ugly worakaround' - // to cover up the mess. - if (browserDetails.browser === 'chrome' && browserDetails.version >= 76) { - var _getConfiguration = this.getConfiguration(), - sdpSemantics = _getConfiguration.sdpSemantics; - - if (sdpSemantics === 'plan-b') { - Object.defineProperty(this, 'sctp', { - get: function get() { - return typeof this._sctp === 'undefined' ? null : this._sctp; - }, - - enumerable: true, - configurable: true - }); - } - } - - if (sctpInDescription(arguments[0])) { - // Check if the remote is FF. - var isFirefox = getRemoteFirefoxVersion(arguments[0]); - - // Get the maximum message size the local peer is capable of sending - var canSendMMS = getCanSendMaxMessageSize(isFirefox); - - // Get the maximum message size of the remote peer. - var remoteMMS = getMaxMessageSize(arguments[0], isFirefox); - - // Determine final maximum message size - var maxMessageSize = void 0; - if (canSendMMS === 0 && remoteMMS === 0) { - maxMessageSize = Number.POSITIVE_INFINITY; - } else if (canSendMMS === 0 || remoteMMS === 0) { - maxMessageSize = Math.max(canSendMMS, remoteMMS); - } else { - maxMessageSize = Math.min(canSendMMS, remoteMMS); - } - - // Create a dummy RTCSctpTransport object and the 'maxMessageSize' - // attribute. - var sctp = {}; - Object.defineProperty(sctp, 'maxMessageSize', { - get: function get() { - return maxMessageSize; - } - }); - this._sctp = sctp; - } - - return origSetRemoteDescription.apply(this, arguments); - }; -} - -function shimSendThrowTypeError(window) { - if (!(window.RTCPeerConnection && 'createDataChannel' in window.RTCPeerConnection.prototype)) { - return; - } - - // Note: Although Firefox >= 57 has a native implementation, the maximum - // message size can be reset for all data channels at a later stage. - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 - - function wrapDcSend(dc, pc) { - var origDataChannelSend = dc.send; - dc.send = function send() { - var data = arguments[0]; - var length = data.length || data.size || data.byteLength; - if (dc.readyState === 'open' && pc.sctp && length > pc.sctp.maxMessageSize) { - throw new TypeError('Message too large (can send a maximum of ' + pc.sctp.maxMessageSize + ' bytes)'); - } - return origDataChannelSend.apply(dc, arguments); - }; - } - var origCreateDataChannel = window.RTCPeerConnection.prototype.createDataChannel; - window.RTCPeerConnection.prototype.createDataChannel = function createDataChannel() { - var dataChannel = origCreateDataChannel.apply(this, arguments); - wrapDcSend(dataChannel, this); - return dataChannel; - }; - utils.wrapPeerConnectionEvent(window, 'datachannel', function (e) { - wrapDcSend(e.channel, e.target); - return e; - }); -} - -/* shims RTCConnectionState by pretending it is the same as iceConnectionState. - * See https://bugs.chromium.org/p/webrtc/issues/detail?id=6145#c12 - * for why this is a valid hack in Chrome. In Firefox it is slightly incorrect - * since DTLS failures would be hidden. See - * https://bugzilla.mozilla.org/show_bug.cgi?id=1265827 - * for the Firefox tracking bug. - */ -function shimConnectionState(window) { - if (!window.RTCPeerConnection || 'connectionState' in window.RTCPeerConnection.prototype) { - return; - } - var proto = window.RTCPeerConnection.prototype; - Object.defineProperty(proto, 'connectionState', { - get: function get() { - return { - completed: 'connected', - checking: 'connecting' - }[this.iceConnectionState] || this.iceConnectionState; - }, - - enumerable: true, - configurable: true - }); - Object.defineProperty(proto, 'onconnectionstatechange', { - get: function get() { - return this._onconnectionstatechange || null; - }, - set: function set(cb) { - if (this._onconnectionstatechange) { - this.removeEventListener('connectionstatechange', this._onconnectionstatechange); - delete this._onconnectionstatechange; - } - if (cb) { - this.addEventListener('connectionstatechange', this._onconnectionstatechange = cb); - } - }, - - enumerable: true, - configurable: true - }); - - ['setLocalDescription', 'setRemoteDescription'].forEach(function (method) { - var origMethod = proto[method]; - proto[method] = function () { - if (!this._connectionstatechangepoly) { - this._connectionstatechangepoly = function (e) { - var pc = e.target; - if (pc._lastConnectionState !== pc.connectionState) { - pc._lastConnectionState = pc.connectionState; - var newEvent = new Event('connectionstatechange', e); - pc.dispatchEvent(newEvent); - } - return e; - }; - this.addEventListener('iceconnectionstatechange', this._connectionstatechangepoly); - } - return origMethod.apply(this, arguments); - }; - }); -} - -function removeAllowExtmapMixed(window) { - /* remove a=extmap-allow-mixed for webrtc.org < M71 */ - if (!window.RTCPeerConnection) { - return; - } - var browserDetails = utils.detectBrowser(window); - if (browserDetails.browser === 'chrome' && browserDetails.version >= 71) { - return; - } - if (browserDetails.browser === 'safari' && browserDetails.version >= 605) { - return; - } - var nativeSRD = window.RTCPeerConnection.prototype.setRemoteDescription; - window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription(desc) { - if (desc && desc.sdp && desc.sdp.indexOf('\na=extmap-allow-mixed') !== -1) { - desc.sdp = desc.sdp.split('\n').filter(function (line) { - return line.trim() !== 'a=extmap-allow-mixed'; - }).join('\n'); - } - return nativeSRD.apply(this, arguments); - }; -} - -},{"./utils":15,"sdp":17}],7:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ -/* eslint-env node */ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined; - -var _getusermedia = require('./getusermedia'); - -Object.defineProperty(exports, 'shimGetUserMedia', { - enumerable: true, - get: function get() { - return _getusermedia.shimGetUserMedia; - } -}); - -var _getdisplaymedia = require('./getdisplaymedia'); - -Object.defineProperty(exports, 'shimGetDisplayMedia', { - enumerable: true, - get: function get() { - return _getdisplaymedia.shimGetDisplayMedia; - } -}); -exports.shimPeerConnection = shimPeerConnection; -exports.shimReplaceTrack = shimReplaceTrack; - -var _utils = require('../utils'); - -var utils = _interopRequireWildcard(_utils); - -var _filtericeservers = require('./filtericeservers'); - -var _rtcpeerconnectionShim = require('rtcpeerconnection-shim'); - -var _rtcpeerconnectionShim2 = _interopRequireDefault(_rtcpeerconnectionShim); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -function shimPeerConnection(window) { - var browserDetails = utils.detectBrowser(window); - - if (window.RTCIceGatherer) { - if (!window.RTCIceCandidate) { - window.RTCIceCandidate = function RTCIceCandidate(args) { - return args; - }; - } - if (!window.RTCSessionDescription) { - window.RTCSessionDescription = function RTCSessionDescription(args) { - return args; - }; - } - // this adds an additional event listener to MediaStrackTrack that signals - // when a tracks enabled property was changed. Workaround for a bug in - // addStream, see below. No longer required in 15025+ - if (browserDetails.version < 15025) { - var origMSTEnabled = Object.getOwnPropertyDescriptor(window.MediaStreamTrack.prototype, 'enabled'); - Object.defineProperty(window.MediaStreamTrack.prototype, 'enabled', { - set: function set(value) { - origMSTEnabled.set.call(this, value); - var ev = new Event('enabled'); - ev.enabled = value; - this.dispatchEvent(ev); - } - }); - } - } - - // ORTC defines the DTMF sender a bit different. - // https://github.com/w3c/ortc/issues/714 - if (window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { - Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { - get: function get() { - if (this._dtmf === undefined) { - if (this.track.kind === 'audio') { - this._dtmf = new window.RTCDtmfSender(this); - } else if (this.track.kind === 'video') { - this._dtmf = null; - } - } - return this._dtmf; - } - }); - } - // Edge currently only implements the RTCDtmfSender, not the - // RTCDTMFSender alias. See http://draft.ortc.org/#rtcdtmfsender2* - if (window.RTCDtmfSender && !window.RTCDTMFSender) { - window.RTCDTMFSender = window.RTCDtmfSender; - } - - var RTCPeerConnectionShim = (0, _rtcpeerconnectionShim2.default)(window, browserDetails.version); - window.RTCPeerConnection = function RTCPeerConnection(config) { - if (config && config.iceServers) { - config.iceServers = (0, _filtericeservers.filterIceServers)(config.iceServers, browserDetails.version); - utils.log('ICE servers after filtering:', config.iceServers); - } - return new RTCPeerConnectionShim(config); - }; - window.RTCPeerConnection.prototype = RTCPeerConnectionShim.prototype; -} - -function shimReplaceTrack(window) { - // ORTC has replaceTrack -- https://github.com/w3c/ortc/issues/614 - if (window.RTCRtpSender && !('replaceTrack' in window.RTCRtpSender.prototype)) { - window.RTCRtpSender.prototype.replaceTrack = window.RTCRtpSender.prototype.setTrack; - } -} - -},{"../utils":15,"./filtericeservers":8,"./getdisplaymedia":9,"./getusermedia":10,"rtcpeerconnection-shim":16}],8:[function(require,module,exports){ -/* - * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ -/* eslint-env node */ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.filterIceServers = filterIceServers; - -var _utils = require('../utils'); - -var utils = _interopRequireWildcard(_utils); - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -// Edge does not like -// 1) stun: filtered after 14393 unless ?transport=udp is present -// 2) turn: that does not have all of turn:host:port?transport=udp -// 3) turn: with ipv6 addresses -// 4) turn: occurring muliple times -function filterIceServers(iceServers, edgeVersion) { - var hasTurn = false; - iceServers = JSON.parse(JSON.stringify(iceServers)); - return iceServers.filter(function (server) { - if (server && (server.urls || server.url)) { - var urls = server.urls || server.url; - if (server.url && !server.urls) { - utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); - } - var isString = typeof urls === 'string'; - if (isString) { - urls = [urls]; - } - urls = urls.filter(function (url) { - // filter STUN unconditionally. - if (url.indexOf('stun:') === 0) { - return false; - } - - var validTurn = url.startsWith('turn') && !url.startsWith('turn:[') && url.includes('transport=udp'); - if (validTurn && !hasTurn) { - hasTurn = true; - return true; - } - return validTurn && !hasTurn; - }); - - delete server.url; - server.urls = isString ? urls[0] : urls; - return !!urls.length; - } - }); -} - -},{"../utils":15}],9:[function(require,module,exports){ -/* - * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ -/* eslint-env node */ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.shimGetDisplayMedia = shimGetDisplayMedia; -function shimGetDisplayMedia(window) { - if (!('getDisplayMedia' in window.navigator)) { - return; - } - if (!window.navigator.mediaDevices) { - return; - } - if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) { - return; - } - window.navigator.mediaDevices.getDisplayMedia = window.navigator.getDisplayMedia.bind(window.navigator); -} - -},{}],10:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ -/* eslint-env node */ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.shimGetUserMedia = shimGetUserMedia; -function shimGetUserMedia(window) { - var navigator = window && window.navigator; - - var shimError_ = function shimError_(e) { - return { - name: { PermissionDeniedError: 'NotAllowedError' }[e.name] || e.name, - message: e.message, - constraint: e.constraint, - toString: function toString() { - return this.name; - } - }; - }; - - // getUserMedia error shim. - var origGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function (c) { - return origGetUserMedia(c).catch(function (e) { - return Promise.reject(shimError_(e)); - }); - }; -} - -},{}],11:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ -/* eslint-env node */ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined; - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - -var _getusermedia = require('./getusermedia'); - -Object.defineProperty(exports, 'shimGetUserMedia', { - enumerable: true, - get: function get() { - return _getusermedia.shimGetUserMedia; - } -}); - -var _getdisplaymedia = require('./getdisplaymedia'); - -Object.defineProperty(exports, 'shimGetDisplayMedia', { - enumerable: true, - get: function get() { - return _getdisplaymedia.shimGetDisplayMedia; - } -}); -exports.shimOnTrack = shimOnTrack; -exports.shimPeerConnection = shimPeerConnection; -exports.shimSenderGetStats = shimSenderGetStats; -exports.shimReceiverGetStats = shimReceiverGetStats; -exports.shimRemoveStream = shimRemoveStream; -exports.shimRTCDataChannel = shimRTCDataChannel; -exports.shimAddTransceiver = shimAddTransceiver; -exports.shimGetParameters = shimGetParameters; -exports.shimCreateOffer = shimCreateOffer; -exports.shimCreateAnswer = shimCreateAnswer; - -var _utils = require('../utils'); - -var utils = _interopRequireWildcard(_utils); - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - -function shimOnTrack(window) { - if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCTrackEvent && 'receiver' in window.RTCTrackEvent.prototype && !('transceiver' in window.RTCTrackEvent.prototype)) { - Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { - get: function get() { - return { receiver: this.receiver }; - } - }); - } -} - -function shimPeerConnection(window) { - var browserDetails = utils.detectBrowser(window); - - if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !(window.RTCPeerConnection || window.mozRTCPeerConnection)) { - return; // probably media.peerconnection.enabled=false in about:config - } - if (!window.RTCPeerConnection && window.mozRTCPeerConnection) { - // very basic support for old versions. - window.RTCPeerConnection = window.mozRTCPeerConnection; - } - - if (browserDetails.version < 53) { - // shim away need for obsolete RTCIceCandidate/RTCSessionDescription. - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'].forEach(function (method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - var methodObj = _defineProperty({}, method, function () { - arguments[0] = new (method === 'addIceCandidate' ? window.RTCIceCandidate : window.RTCSessionDescription)(arguments[0]); - return nativeMethod.apply(this, arguments); - }); - window.RTCPeerConnection.prototype[method] = methodObj[method]; - }); - } - - // support for addIceCandidate(null or undefined) - // as well as ignoring {sdpMid, candidate: ""} - if (browserDetails.version < 68) { - var nativeAddIceCandidate = window.RTCPeerConnection.prototype.addIceCandidate; - window.RTCPeerConnection.prototype.addIceCandidate = function addIceCandidate() { - if (!arguments[0]) { - if (arguments[1]) { - arguments[1].apply(null); - } - return Promise.resolve(); - } - // Firefox 68+ emits and processes {candidate: "", ...}, ignore - // in older versions. - if (arguments[0] && arguments[0].candidate === '') { - return Promise.resolve(); - } - return nativeAddIceCandidate.apply(this, arguments); - }; - } - - var modernStatsTypes = { - inboundrtp: 'inbound-rtp', - outboundrtp: 'outbound-rtp', - candidatepair: 'candidate-pair', - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }; - - var nativeGetStats = window.RTCPeerConnection.prototype.getStats; - window.RTCPeerConnection.prototype.getStats = function getStats() { - var _arguments = Array.prototype.slice.call(arguments), - selector = _arguments[0], - onSucc = _arguments[1], - onErr = _arguments[2]; - - return nativeGetStats.apply(this, [selector || null]).then(function (stats) { - if (browserDetails.version < 53 && !onSucc) { - // Shim only promise getStats with spec-hyphens in type names - // Leave callback version alone; misc old uses of forEach before Map - try { - stats.forEach(function (stat) { - stat.type = modernStatsTypes[stat.type] || stat.type; - }); - } catch (e) { - if (e.name !== 'TypeError') { - throw e; - } - // Avoid TypeError: "type" is read-only, in old versions. 34-43ish - stats.forEach(function (stat, i) { - stats.set(i, Object.assign({}, stat, { - type: modernStatsTypes[stat.type] || stat.type - })); - }); - } - } - return stats; - }).then(onSucc, onErr); - }; -} - -function shimSenderGetStats(window) { - if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && window.RTCRtpSender)) { - return; - } - if (window.RTCRtpSender && 'getStats' in window.RTCRtpSender.prototype) { - return; - } - var origGetSenders = window.RTCPeerConnection.prototype.getSenders; - if (origGetSenders) { - window.RTCPeerConnection.prototype.getSenders = function getSenders() { - var _this = this; - - var senders = origGetSenders.apply(this, []); - senders.forEach(function (sender) { - return sender._pc = _this; - }); - return senders; - }; - } - - var origAddTrack = window.RTCPeerConnection.prototype.addTrack; - if (origAddTrack) { - window.RTCPeerConnection.prototype.addTrack = function addTrack() { - var sender = origAddTrack.apply(this, arguments); - sender._pc = this; - return sender; - }; - } - window.RTCRtpSender.prototype.getStats = function getStats() { - return this.track ? this._pc.getStats(this.track) : Promise.resolve(new Map()); - }; -} - -function shimReceiverGetStats(window) { - if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && window.RTCRtpSender)) { - return; - } - if (window.RTCRtpSender && 'getStats' in window.RTCRtpReceiver.prototype) { - return; - } - var origGetReceivers = window.RTCPeerConnection.prototype.getReceivers; - if (origGetReceivers) { - window.RTCPeerConnection.prototype.getReceivers = function getReceivers() { - var _this2 = this; - - var receivers = origGetReceivers.apply(this, []); - receivers.forEach(function (receiver) { - return receiver._pc = _this2; - }); - return receivers; - }; - } - utils.wrapPeerConnectionEvent(window, 'track', function (e) { - e.receiver._pc = e.srcElement; - return e; - }); - window.RTCRtpReceiver.prototype.getStats = function getStats() { - return this._pc.getStats(this.track); - }; -} - -function shimRemoveStream(window) { - if (!window.RTCPeerConnection || 'removeStream' in window.RTCPeerConnection.prototype) { - return; - } - window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { - var _this3 = this; - - utils.deprecated('removeStream', 'removeTrack'); - this.getSenders().forEach(function (sender) { - if (sender.track && stream.getTracks().includes(sender.track)) { - _this3.removeTrack(sender); - } - }); - }; -} - -function shimRTCDataChannel(window) { - // rename DataChannel to RTCDataChannel (native fix in FF60): - // https://bugzilla.mozilla.org/show_bug.cgi?id=1173851 - if (window.DataChannel && !window.RTCDataChannel) { - window.RTCDataChannel = window.DataChannel; - } -} - -function shimAddTransceiver(window) { - // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647 - // Firefox ignores the init sendEncodings options passed to addTransceiver - // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 - if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection)) { - return; - } - var origAddTransceiver = window.RTCPeerConnection.prototype.addTransceiver; - if (origAddTransceiver) { - window.RTCPeerConnection.prototype.addTransceiver = function addTransceiver() { - this.setParametersPromises = []; - var initParameters = arguments[1]; - var shouldPerformCheck = initParameters && 'sendEncodings' in initParameters; - if (shouldPerformCheck) { - // If sendEncodings params are provided, validate grammar - initParameters.sendEncodings.forEach(function (encodingParam) { - if ('rid' in encodingParam) { - var ridRegex = /^[a-z0-9]{0,16}$/i; - if (!ridRegex.test(encodingParam.rid)) { - throw new TypeError('Invalid RID value provided.'); - } - } - if ('scaleResolutionDownBy' in encodingParam) { - if (!(parseFloat(encodingParam.scaleResolutionDownBy) >= 1.0)) { - throw new RangeError('scale_resolution_down_by must be >= 1.0'); - } - } - if ('maxFramerate' in encodingParam) { - if (!(parseFloat(encodingParam.maxFramerate) >= 0)) { - throw new RangeError('max_framerate must be >= 0.0'); - } - } - }); - } - var transceiver = origAddTransceiver.apply(this, arguments); - if (shouldPerformCheck) { - // Check if the init options were applied. If not we do this in an - // asynchronous way and save the promise reference in a global object. - // This is an ugly hack, but at the same time is way more robust than - // checking the sender parameters before and after the createOffer - // Also note that after the createoffer we are not 100% sure that - // the params were asynchronously applied so we might miss the - // opportunity to recreate offer. - var sender = transceiver.sender; - - var params = sender.getParameters(); - if (!('encodings' in params) || - // Avoid being fooled by patched getParameters() below. - params.encodings.length === 1 && Object.keys(params.encodings[0]).length === 0) { - params.encodings = initParameters.sendEncodings; - sender.sendEncodings = initParameters.sendEncodings; - this.setParametersPromises.push(sender.setParameters(params).then(function () { - delete sender.sendEncodings; - }).catch(function () { - delete sender.sendEncodings; - })); - } - } - return transceiver; - }; - } -} - -function shimGetParameters(window) { - if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCRtpSender)) { - return; - } - var origGetParameters = window.RTCRtpSender.prototype.getParameters; - if (origGetParameters) { - window.RTCRtpSender.prototype.getParameters = function getParameters() { - var params = origGetParameters.apply(this, arguments); - if (!('encodings' in params)) { - params.encodings = [].concat(this.sendEncodings || [{}]); - } - return params; - }; - } -} - -function shimCreateOffer(window) { - // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647 - // Firefox ignores the init sendEncodings options passed to addTransceiver - // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 - if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection)) { - return; - } - var origCreateOffer = window.RTCPeerConnection.prototype.createOffer; - window.RTCPeerConnection.prototype.createOffer = function createOffer() { - var _this4 = this, - _arguments2 = arguments; - - if (this.setParametersPromises && this.setParametersPromises.length) { - return Promise.all(this.setParametersPromises).then(function () { - return origCreateOffer.apply(_this4, _arguments2); - }).finally(function () { - _this4.setParametersPromises = []; - }); - } - return origCreateOffer.apply(this, arguments); - }; -} - -function shimCreateAnswer(window) { - // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647 - // Firefox ignores the init sendEncodings options passed to addTransceiver - // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 - if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection)) { - return; - } - var origCreateAnswer = window.RTCPeerConnection.prototype.createAnswer; - window.RTCPeerConnection.prototype.createAnswer = function createAnswer() { - var _this5 = this, - _arguments3 = arguments; - - if (this.setParametersPromises && this.setParametersPromises.length) { - return Promise.all(this.setParametersPromises).then(function () { - return origCreateAnswer.apply(_this5, _arguments3); - }).finally(function () { - _this5.setParametersPromises = []; - }); - } - return origCreateAnswer.apply(this, arguments); - }; -} - -},{"../utils":15,"./getdisplaymedia":12,"./getusermedia":13}],12:[function(require,module,exports){ -/* - * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ -/* eslint-env node */ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.shimGetDisplayMedia = shimGetDisplayMedia; -function shimGetDisplayMedia(window, preferredMediaSource) { - if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) { - return; - } - if (!window.navigator.mediaDevices) { - return; - } - window.navigator.mediaDevices.getDisplayMedia = function getDisplayMedia(constraints) { - if (!(constraints && constraints.video)) { - var err = new DOMException('getDisplayMedia without video ' + 'constraints is undefined'); - err.name = 'NotFoundError'; - // from https://heycam.github.io/webidl/#idl-DOMException-error-names - err.code = 8; - return Promise.reject(err); - } - if (constraints.video === true) { - constraints.video = { mediaSource: preferredMediaSource }; - } else { - constraints.video.mediaSource = preferredMediaSource; - } - return window.navigator.mediaDevices.getUserMedia(constraints); - }; -} - -},{}],13:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ -/* eslint-env node */ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - -exports.shimGetUserMedia = shimGetUserMedia; - -var _utils = require('../utils'); - -var utils = _interopRequireWildcard(_utils); - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -function shimGetUserMedia(window) { - var browserDetails = utils.detectBrowser(window); - var navigator = window && window.navigator; - var MediaStreamTrack = window && window.MediaStreamTrack; - - navigator.getUserMedia = function (constraints, onSuccess, onError) { - // Replace Firefox 44+'s deprecation warning with unprefixed version. - utils.deprecated('navigator.getUserMedia', 'navigator.mediaDevices.getUserMedia'); - navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError); - }; - - if (!(browserDetails.version > 55 && 'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) { - var remap = function remap(obj, a, b) { - if (a in obj && !(b in obj)) { - obj[b] = obj[a]; - delete obj[a]; - } - }; - - var nativeGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function (c) { - if ((typeof c === 'undefined' ? 'undefined' : _typeof(c)) === 'object' && _typeof(c.audio) === 'object') { - c = JSON.parse(JSON.stringify(c)); - remap(c.audio, 'autoGainControl', 'mozAutoGainControl'); - remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression'); - } - return nativeGetUserMedia(c); - }; - - if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) { - var nativeGetSettings = MediaStreamTrack.prototype.getSettings; - MediaStreamTrack.prototype.getSettings = function () { - var obj = nativeGetSettings.apply(this, arguments); - remap(obj, 'mozAutoGainControl', 'autoGainControl'); - remap(obj, 'mozNoiseSuppression', 'noiseSuppression'); - return obj; - }; - } - - if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) { - var nativeApplyConstraints = MediaStreamTrack.prototype.applyConstraints; - MediaStreamTrack.prototype.applyConstraints = function (c) { - if (this.kind === 'audio' && (typeof c === 'undefined' ? 'undefined' : _typeof(c)) === 'object') { - c = JSON.parse(JSON.stringify(c)); - remap(c, 'autoGainControl', 'mozAutoGainControl'); - remap(c, 'noiseSuppression', 'mozNoiseSuppression'); - } - return nativeApplyConstraints.apply(this, [c]); - }; - } - } -} - -},{"../utils":15}],14:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - -exports.shimLocalStreamsAPI = shimLocalStreamsAPI; -exports.shimRemoteStreamsAPI = shimRemoteStreamsAPI; -exports.shimCallbacksAPI = shimCallbacksAPI; -exports.shimGetUserMedia = shimGetUserMedia; -exports.shimConstraints = shimConstraints; -exports.shimRTCIceServerUrls = shimRTCIceServerUrls; -exports.shimTrackEventTransceiver = shimTrackEventTransceiver; -exports.shimCreateOfferLegacy = shimCreateOfferLegacy; -exports.shimAudioContext = shimAudioContext; - -var _utils = require('../utils'); - -var utils = _interopRequireWildcard(_utils); - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -function shimLocalStreamsAPI(window) { - if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !window.RTCPeerConnection) { - return; - } - if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() { - if (!this._localStreams) { - this._localStreams = []; - } - return this._localStreams; - }; - } - if (!('addStream' in window.RTCPeerConnection.prototype)) { - var _addTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addStream = function addStream(stream) { - var _this = this; - - if (!this._localStreams) { - this._localStreams = []; - } - if (!this._localStreams.includes(stream)) { - this._localStreams.push(stream); - } - // Try to emulate Chrome's behaviour of adding in audio-video order. - // Safari orders by track id. - stream.getAudioTracks().forEach(function (track) { - return _addTrack.call(_this, track, stream); - }); - stream.getVideoTracks().forEach(function (track) { - return _addTrack.call(_this, track, stream); - }); - }; - - window.RTCPeerConnection.prototype.addTrack = function addTrack(track) { - var _this2 = this; - - for (var _len = arguments.length, streams = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - streams[_key - 1] = arguments[_key]; - } - - if (streams) { - streams.forEach(function (stream) { - if (!_this2._localStreams) { - _this2._localStreams = [stream]; - } else if (!_this2._localStreams.includes(stream)) { - _this2._localStreams.push(stream); - } - }); - } - return _addTrack.apply(this, arguments); - }; - } - if (!('removeStream' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { - var _this3 = this; - - if (!this._localStreams) { - this._localStreams = []; - } - var index = this._localStreams.indexOf(stream); - if (index === -1) { - return; - } - this._localStreams.splice(index, 1); - var tracks = stream.getTracks(); - this.getSenders().forEach(function (sender) { - if (tracks.includes(sender.track)) { - _this3.removeTrack(sender); - } - }); - }; - } -} - -function shimRemoteStreamsAPI(window) { - if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !window.RTCPeerConnection) { - return; - } - if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getRemoteStreams = function getRemoteStreams() { - return this._remoteStreams ? this._remoteStreams : []; - }; - } - if (!('onaddstream' in window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', { - get: function get() { - return this._onaddstream; - }, - set: function set(f) { - var _this4 = this; - - if (this._onaddstream) { - this.removeEventListener('addstream', this._onaddstream); - this.removeEventListener('track', this._onaddstreampoly); - } - this.addEventListener('addstream', this._onaddstream = f); - this.addEventListener('track', this._onaddstreampoly = function (e) { - e.streams.forEach(function (stream) { - if (!_this4._remoteStreams) { - _this4._remoteStreams = []; - } - if (_this4._remoteStreams.includes(stream)) { - return; - } - _this4._remoteStreams.push(stream); - var event = new Event('addstream'); - event.stream = stream; - _this4.dispatchEvent(event); - }); - }); - } - }); - var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; - window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() { - var pc = this; - if (!this._onaddstreampoly) { - this.addEventListener('track', this._onaddstreampoly = function (e) { - e.streams.forEach(function (stream) { - if (!pc._remoteStreams) { - pc._remoteStreams = []; - } - if (pc._remoteStreams.indexOf(stream) >= 0) { - return; - } - pc._remoteStreams.push(stream); - var event = new Event('addstream'); - event.stream = stream; - pc.dispatchEvent(event); - }); - }); - } - return origSetRemoteDescription.apply(pc, arguments); - }; - } -} - -function shimCallbacksAPI(window) { - if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !window.RTCPeerConnection) { - return; - } - var prototype = window.RTCPeerConnection.prototype; - var origCreateOffer = prototype.createOffer; - var origCreateAnswer = prototype.createAnswer; - var setLocalDescription = prototype.setLocalDescription; - var setRemoteDescription = prototype.setRemoteDescription; - var addIceCandidate = prototype.addIceCandidate; - - prototype.createOffer = function createOffer(successCallback, failureCallback) { - var options = arguments.length >= 2 ? arguments[2] : arguments[0]; - var promise = origCreateOffer.apply(this, [options]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - - prototype.createAnswer = function createAnswer(successCallback, failureCallback) { - var options = arguments.length >= 2 ? arguments[2] : arguments[0]; - var promise = origCreateAnswer.apply(this, [options]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - - var withCallback = function withCallback(description, successCallback, failureCallback) { - var promise = setLocalDescription.apply(this, [description]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.setLocalDescription = withCallback; - - withCallback = function withCallback(description, successCallback, failureCallback) { - var promise = setRemoteDescription.apply(this, [description]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.setRemoteDescription = withCallback; - - withCallback = function withCallback(candidate, successCallback, failureCallback) { - var promise = addIceCandidate.apply(this, [candidate]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.addIceCandidate = withCallback; -} - -function shimGetUserMedia(window) { - var navigator = window && window.navigator; - - if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { - // shim not needed in Safari 12.1 - var mediaDevices = navigator.mediaDevices; - var _getUserMedia = mediaDevices.getUserMedia.bind(mediaDevices); - navigator.mediaDevices.getUserMedia = function (constraints) { - return _getUserMedia(shimConstraints(constraints)); - }; - } - - if (!navigator.getUserMedia && navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { - navigator.getUserMedia = function getUserMedia(constraints, cb, errcb) { - navigator.mediaDevices.getUserMedia(constraints).then(cb, errcb); - }.bind(navigator); - } -} - -function shimConstraints(constraints) { - if (constraints && constraints.video !== undefined) { - return Object.assign({}, constraints, { video: utils.compactObject(constraints.video) }); - } - - return constraints; -} - -function shimRTCIceServerUrls(window) { - if (!window.RTCPeerConnection) { - return; - } - // migrate from non-spec RTCIceServer.url to RTCIceServer.urls - var OrigPeerConnection = window.RTCPeerConnection; - window.RTCPeerConnection = function RTCPeerConnection(pcConfig, pcConstraints) { - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (!server.hasOwnProperty('urls') && server.hasOwnProperty('url')) { - utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); - server = JSON.parse(JSON.stringify(server)); - server.urls = server.url; - delete server.url; - newIceServers.push(server); - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - return new OrigPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - if ('generateCertificate' in OrigPeerConnection) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function get() { - return OrigPeerConnection.generateCertificate; - } - }); - } -} - -function shimTrackEventTransceiver(window) { - // Add event.transceiver member over deprecated event.receiver - if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCTrackEvent && 'receiver' in window.RTCTrackEvent.prototype && !('transceiver' in window.RTCTrackEvent.prototype)) { - Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { - get: function get() { - return { receiver: this.receiver }; - } - }); - } -} - -function shimCreateOfferLegacy(window) { - var origCreateOffer = window.RTCPeerConnection.prototype.createOffer; - window.RTCPeerConnection.prototype.createOffer = function createOffer(offerOptions) { - if (offerOptions) { - if (typeof offerOptions.offerToReceiveAudio !== 'undefined') { - // support bit values - offerOptions.offerToReceiveAudio = !!offerOptions.offerToReceiveAudio; - } - var audioTransceiver = this.getTransceivers().find(function (transceiver) { - return transceiver.receiver.track.kind === 'audio'; - }); - if (offerOptions.offerToReceiveAudio === false && audioTransceiver) { - if (audioTransceiver.direction === 'sendrecv') { - if (audioTransceiver.setDirection) { - audioTransceiver.setDirection('sendonly'); - } else { - audioTransceiver.direction = 'sendonly'; - } - } else if (audioTransceiver.direction === 'recvonly') { - if (audioTransceiver.setDirection) { - audioTransceiver.setDirection('inactive'); - } else { - audioTransceiver.direction = 'inactive'; - } - } - } else if (offerOptions.offerToReceiveAudio === true && !audioTransceiver) { - this.addTransceiver('audio'); - } - - if (typeof offerOptions.offerToReceiveVideo !== 'undefined') { - // support bit values - offerOptions.offerToReceiveVideo = !!offerOptions.offerToReceiveVideo; - } - var videoTransceiver = this.getTransceivers().find(function (transceiver) { - return transceiver.receiver.track.kind === 'video'; - }); - if (offerOptions.offerToReceiveVideo === false && videoTransceiver) { - if (videoTransceiver.direction === 'sendrecv') { - if (videoTransceiver.setDirection) { - videoTransceiver.setDirection('sendonly'); - } else { - videoTransceiver.direction = 'sendonly'; - } - } else if (videoTransceiver.direction === 'recvonly') { - if (videoTransceiver.setDirection) { - videoTransceiver.setDirection('inactive'); - } else { - videoTransceiver.direction = 'inactive'; - } - } - } else if (offerOptions.offerToReceiveVideo === true && !videoTransceiver) { - this.addTransceiver('video'); - } - } - return origCreateOffer.apply(this, arguments); - }; -} - -function shimAudioContext(window) { - if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || window.AudioContext) { - return; - } - window.AudioContext = window.webkitAudioContext; -} - -},{"../utils":15}],15:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ -/* eslint-env node */ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - -exports.extractVersion = extractVersion; -exports.wrapPeerConnectionEvent = wrapPeerConnectionEvent; -exports.disableLog = disableLog; -exports.disableWarnings = disableWarnings; -exports.log = log; -exports.deprecated = deprecated; -exports.detectBrowser = detectBrowser; -exports.compactObject = compactObject; -exports.walkStats = walkStats; -exports.filterStats = filterStats; - -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - -var logDisabled_ = true; -var deprecationWarnings_ = true; - -/** - * Extract browser version out of the provided user agent string. - * - * @param {!string} uastring userAgent string. - * @param {!string} expr Regular expression used as match criteria. - * @param {!number} pos position in the version string to be returned. - * @return {!number} browser version. - */ -function extractVersion(uastring, expr, pos) { - var match = uastring.match(expr); - return match && match.length >= pos && parseInt(match[pos], 10); -} - -// Wraps the peerconnection event eventNameToWrap in a function -// which returns the modified event object (or false to prevent -// the event). -function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) { - if (!window.RTCPeerConnection) { - return; - } - var proto = window.RTCPeerConnection.prototype; - var nativeAddEventListener = proto.addEventListener; - proto.addEventListener = function (nativeEventName, cb) { - if (nativeEventName !== eventNameToWrap) { - return nativeAddEventListener.apply(this, arguments); - } - var wrappedCallback = function wrappedCallback(e) { - var modifiedEvent = wrapper(e); - if (modifiedEvent) { - if (cb.handleEvent) { - cb.handleEvent(modifiedEvent); - } else { - cb(modifiedEvent); - } - } - }; - this._eventMap = this._eventMap || {}; - if (!this._eventMap[eventNameToWrap]) { - this._eventMap[eventNameToWrap] = new Map(); - } - this._eventMap[eventNameToWrap].set(cb, wrappedCallback); - return nativeAddEventListener.apply(this, [nativeEventName, wrappedCallback]); - }; - - var nativeRemoveEventListener = proto.removeEventListener; - proto.removeEventListener = function (nativeEventName, cb) { - if (nativeEventName !== eventNameToWrap || !this._eventMap || !this._eventMap[eventNameToWrap]) { - return nativeRemoveEventListener.apply(this, arguments); - } - if (!this._eventMap[eventNameToWrap].has(cb)) { - return nativeRemoveEventListener.apply(this, arguments); - } - var unwrappedCb = this._eventMap[eventNameToWrap].get(cb); - this._eventMap[eventNameToWrap].delete(cb); - if (this._eventMap[eventNameToWrap].size === 0) { - delete this._eventMap[eventNameToWrap]; - } - if (Object.keys(this._eventMap).length === 0) { - delete this._eventMap; - } - return nativeRemoveEventListener.apply(this, [nativeEventName, unwrappedCb]); - }; - - Object.defineProperty(proto, 'on' + eventNameToWrap, { - get: function get() { - return this['_on' + eventNameToWrap]; - }, - set: function set(cb) { - if (this['_on' + eventNameToWrap]) { - this.removeEventListener(eventNameToWrap, this['_on' + eventNameToWrap]); - delete this['_on' + eventNameToWrap]; - } - if (cb) { - this.addEventListener(eventNameToWrap, this['_on' + eventNameToWrap] = cb); - } - }, - - enumerable: true, - configurable: true - }); -} - -function disableLog(bool) { - if (typeof bool !== 'boolean') { - return new Error('Argument type: ' + (typeof bool === 'undefined' ? 'undefined' : _typeof(bool)) + '. Please use a boolean.'); - } - logDisabled_ = bool; - return bool ? 'adapter.js logging disabled' : 'adapter.js logging enabled'; -} - -/** - * Disable or enable deprecation warnings - * @param {!boolean} bool set to true to disable warnings. - */ -function disableWarnings(bool) { - if (typeof bool !== 'boolean') { - return new Error('Argument type: ' + (typeof bool === 'undefined' ? 'undefined' : _typeof(bool)) + '. Please use a boolean.'); - } - deprecationWarnings_ = !bool; - return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled'); -} - -function log() { - if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object') { - if (logDisabled_) { - return; - } - if (typeof console !== 'undefined' && typeof console.log === 'function') { - console.log.apply(console, arguments); - } - } -} - -/** - * Shows a deprecation warning suggesting the modern and spec-compatible API. - */ -function deprecated(oldMethod, newMethod) { - if (!deprecationWarnings_) { - return; - } - console.warn(oldMethod + ' is deprecated, please use ' + newMethod + ' instead.'); -} - -/** - * Browser detector. - * - * @return {object} result containing browser and version - * properties. - */ -function detectBrowser(window) { - // Returned result object. - var result = { browser: null, version: null }; - - // Fail early if it's not a browser - if (typeof window === 'undefined' || !window.navigator) { - result.browser = 'Not a browser.'; - return result; - } - - var navigator = window.navigator; - - - if (navigator.mozGetUserMedia) { - // Firefox. - result.browser = 'firefox'; - result.version = extractVersion(navigator.userAgent, /Firefox\/(\d+)\./, 1); - } else if (navigator.webkitGetUserMedia || window.isSecureContext === false && window.webkitRTCPeerConnection && !window.RTCIceGatherer) { - // Chrome, Chromium, Webview, Opera. - // Version matches Chrome/WebRTC version. - // Chrome 74 removed webkitGetUserMedia on http as well so we need the - // more complicated fallback to webkitRTCPeerConnection. - result.browser = 'chrome'; - result.version = extractVersion(navigator.userAgent, /Chrom(e|ium)\/(\d+)\./, 2); - } else if (navigator.mediaDevices && navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) { - // Edge. - result.browser = 'edge'; - result.version = extractVersion(navigator.userAgent, /Edge\/(\d+).(\d+)$/, 2); - } else if (window.RTCPeerConnection && navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) { - // Safari. - result.browser = 'safari'; - result.version = extractVersion(navigator.userAgent, /AppleWebKit\/(\d+)\./, 1); - result.supportsUnifiedPlan = window.RTCRtpTransceiver && 'currentDirection' in window.RTCRtpTransceiver.prototype; - } else { - // Default fallthrough: not supported. - result.browser = 'Not a supported browser.'; - return result; - } - - return result; -} - -/** - * Checks if something is an object. - * - * @param {*} val The something you want to check. - * @return true if val is an object, false otherwise. - */ -function isObject(val) { - return Object.prototype.toString.call(val) === '[object Object]'; -} - -/** - * Remove all empty objects and undefined values - * from a nested object -- an enhanced and vanilla version - * of Lodash's `compact`. - */ -function compactObject(data) { - if (!isObject(data)) { - return data; - } - - return Object.keys(data).reduce(function (accumulator, key) { - var isObj = isObject(data[key]); - var value = isObj ? compactObject(data[key]) : data[key]; - var isEmptyObject = isObj && !Object.keys(value).length; - if (value === undefined || isEmptyObject) { - return accumulator; - } - return Object.assign(accumulator, _defineProperty({}, key, value)); - }, {}); -} - -/* iterates the stats graph recursively. */ -function walkStats(stats, base, resultSet) { - if (!base || resultSet.has(base.id)) { - return; - } - resultSet.set(base.id, base); - Object.keys(base).forEach(function (name) { - if (name.endsWith('Id')) { - walkStats(stats, stats.get(base[name]), resultSet); - } else if (name.endsWith('Ids')) { - base[name].forEach(function (id) { - walkStats(stats, stats.get(id), resultSet); - }); - } - }); -} - -/* filter getStats for a sender/receiver track. */ -function filterStats(result, track, outbound) { - var streamStatsType = outbound ? 'outbound-rtp' : 'inbound-rtp'; - var filteredResult = new Map(); - if (track === null) { - return filteredResult; - } - var trackStats = []; - result.forEach(function (value) { - if (value.type === 'track' && value.trackIdentifier === track.id) { - trackStats.push(value); - } - }); - trackStats.forEach(function (trackStat) { - result.forEach(function (stats) { - if (stats.type === streamStatsType && stats.trackId === trackStat.id) { - walkStats(result, stats, filteredResult); - } - }); - }); - return filteredResult; -} - -},{}],16:[function(require,module,exports){ -/* - * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var SDPUtils = require('sdp'); - -function fixStatsType(stat) { - return { - inboundrtp: 'inbound-rtp', - outboundrtp: 'outbound-rtp', - candidatepair: 'candidate-pair', - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }[stat.type] || stat.type; -} - -function writeMediaSection(transceiver, caps, type, stream, dtlsRole) { - var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps); - - // Map ICE parameters (ufrag, pwd) to SDP. - sdp += SDPUtils.writeIceParameters( - transceiver.iceGatherer.getLocalParameters()); - - // Map DTLS parameters to SDP. - sdp += SDPUtils.writeDtlsParameters( - transceiver.dtlsTransport.getLocalParameters(), - type === 'offer' ? 'actpass' : dtlsRole || 'active'); - - sdp += 'a=mid:' + transceiver.mid + '\r\n'; - - if (transceiver.rtpSender && transceiver.rtpReceiver) { - sdp += 'a=sendrecv\r\n'; - } else if (transceiver.rtpSender) { - sdp += 'a=sendonly\r\n'; - } else if (transceiver.rtpReceiver) { - sdp += 'a=recvonly\r\n'; - } else { - sdp += 'a=inactive\r\n'; - } - - if (transceiver.rtpSender) { - var trackId = transceiver.rtpSender._initialTrackId || - transceiver.rtpSender.track.id; - transceiver.rtpSender._initialTrackId = trackId; - // spec. - var msid = 'msid:' + (stream ? stream.id : '-') + ' ' + - trackId + '\r\n'; - sdp += 'a=' + msid; - // for Chrome. Legacy should no longer be required. - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + - ' ' + msid; - - // RTX - if (transceiver.sendEncodingParameters[0].rtx) { - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + - ' ' + msid; - sdp += 'a=ssrc-group:FID ' + - transceiver.sendEncodingParameters[0].ssrc + ' ' + - transceiver.sendEncodingParameters[0].rtx.ssrc + - '\r\n'; - } - } - // FIXME: this should be written by writeRtpDescription. - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + - ' cname:' + SDPUtils.localCName + '\r\n'; - if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) { - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + - ' cname:' + SDPUtils.localCName + '\r\n'; - } - return sdp; -} - -// Edge does not like -// 1) stun: filtered after 14393 unless ?transport=udp is present -// 2) turn: that does not have all of turn:host:port?transport=udp -// 3) turn: with ipv6 addresses -// 4) turn: occurring muliple times -function filterIceServers(iceServers, edgeVersion) { - var hasTurn = false; - iceServers = JSON.parse(JSON.stringify(iceServers)); - return iceServers.filter(function(server) { - if (server && (server.urls || server.url)) { - var urls = server.urls || server.url; - if (server.url && !server.urls) { - console.warn('RTCIceServer.url is deprecated! Use urls instead.'); - } - var isString = typeof urls === 'string'; - if (isString) { - urls = [urls]; - } - urls = urls.filter(function(url) { - var validTurn = url.indexOf('turn:') === 0 && - url.indexOf('transport=udp') !== -1 && - url.indexOf('turn:[') === -1 && - !hasTurn; - - if (validTurn) { - hasTurn = true; - return true; - } - return url.indexOf('stun:') === 0 && edgeVersion >= 14393 && - url.indexOf('?transport=udp') === -1; - }); - - delete server.url; - server.urls = isString ? urls[0] : urls; - return !!urls.length; - } - }); -} - -// Determines the intersection of local and remote capabilities. -function getCommonCapabilities(localCapabilities, remoteCapabilities) { - var commonCapabilities = { - codecs: [], - headerExtensions: [], - fecMechanisms: [] - }; - - var findCodecByPayloadType = function(pt, codecs) { - pt = parseInt(pt, 10); - for (var i = 0; i < codecs.length; i++) { - if (codecs[i].payloadType === pt || - codecs[i].preferredPayloadType === pt) { - return codecs[i]; - } - } - }; - - var rtxCapabilityMatches = function(lRtx, rRtx, lCodecs, rCodecs) { - var lCodec = findCodecByPayloadType(lRtx.parameters.apt, lCodecs); - var rCodec = findCodecByPayloadType(rRtx.parameters.apt, rCodecs); - return lCodec && rCodec && - lCodec.name.toLowerCase() === rCodec.name.toLowerCase(); - }; - - localCapabilities.codecs.forEach(function(lCodec) { - for (var i = 0; i < remoteCapabilities.codecs.length; i++) { - var rCodec = remoteCapabilities.codecs[i]; - if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() && - lCodec.clockRate === rCodec.clockRate) { - if (lCodec.name.toLowerCase() === 'rtx' && - lCodec.parameters && rCodec.parameters.apt) { - // for RTX we need to find the local rtx that has a apt - // which points to the same local codec as the remote one. - if (!rtxCapabilityMatches(lCodec, rCodec, - localCapabilities.codecs, remoteCapabilities.codecs)) { - continue; - } - } - rCodec = JSON.parse(JSON.stringify(rCodec)); // deepcopy - // number of channels is the highest common number of channels - rCodec.numChannels = Math.min(lCodec.numChannels, - rCodec.numChannels); - // push rCodec so we reply with offerer payload type - commonCapabilities.codecs.push(rCodec); - - // determine common feedback mechanisms - rCodec.rtcpFeedback = rCodec.rtcpFeedback.filter(function(fb) { - for (var j = 0; j < lCodec.rtcpFeedback.length; j++) { - if (lCodec.rtcpFeedback[j].type === fb.type && - lCodec.rtcpFeedback[j].parameter === fb.parameter) { - return true; - } - } - return false; - }); - // FIXME: also need to determine .parameters - // see https://github.com/openpeer/ortc/issues/569 - break; - } - } - }); - - localCapabilities.headerExtensions.forEach(function(lHeaderExtension) { - for (var i = 0; i < remoteCapabilities.headerExtensions.length; - i++) { - var rHeaderExtension = remoteCapabilities.headerExtensions[i]; - if (lHeaderExtension.uri === rHeaderExtension.uri) { - commonCapabilities.headerExtensions.push(rHeaderExtension); - break; - } - } - }); - - // FIXME: fecMechanisms - return commonCapabilities; -} - -// is action=setLocalDescription with type allowed in signalingState -function isActionAllowedInSignalingState(action, type, signalingState) { - return { - offer: { - setLocalDescription: ['stable', 'have-local-offer'], - setRemoteDescription: ['stable', 'have-remote-offer'] - }, - answer: { - setLocalDescription: ['have-remote-offer', 'have-local-pranswer'], - setRemoteDescription: ['have-local-offer', 'have-remote-pranswer'] - } - }[type][action].indexOf(signalingState) !== -1; -} - -function maybeAddCandidate(iceTransport, candidate) { - // Edge's internal representation adds some fields therefore - // not all fieldѕ are taken into account. - var alreadyAdded = iceTransport.getRemoteCandidates() - .find(function(remoteCandidate) { - return candidate.foundation === remoteCandidate.foundation && - candidate.ip === remoteCandidate.ip && - candidate.port === remoteCandidate.port && - candidate.priority === remoteCandidate.priority && - candidate.protocol === remoteCandidate.protocol && - candidate.type === remoteCandidate.type; - }); - if (!alreadyAdded) { - iceTransport.addRemoteCandidate(candidate); - } - return !alreadyAdded; -} - - -function makeError(name, description) { - var e = new Error(description); - e.name = name; - // legacy error codes from https://heycam.github.io/webidl/#idl-DOMException-error-names - e.code = { - NotSupportedError: 9, - InvalidStateError: 11, - InvalidAccessError: 15, - TypeError: undefined, - OperationError: undefined - }[name]; - return e; -} - -module.exports = function(window, edgeVersion) { - // https://w3c.github.io/mediacapture-main/#mediastream - // Helper function to add the track to the stream and - // dispatch the event ourselves. - function addTrackToStreamAndFireEvent(track, stream) { - stream.addTrack(track); - stream.dispatchEvent(new window.MediaStreamTrackEvent('addtrack', - {track: track})); - } - - function removeTrackFromStreamAndFireEvent(track, stream) { - stream.removeTrack(track); - stream.dispatchEvent(new window.MediaStreamTrackEvent('removetrack', - {track: track})); - } - - function fireAddTrack(pc, track, receiver, streams) { - var trackEvent = new Event('track'); - trackEvent.track = track; - trackEvent.receiver = receiver; - trackEvent.transceiver = {receiver: receiver}; - trackEvent.streams = streams; - window.setTimeout(function() { - pc._dispatchEvent('track', trackEvent); - }); - } - - var RTCPeerConnection = function(config) { - var pc = this; - - var _eventTarget = document.createDocumentFragment(); - ['addEventListener', 'removeEventListener', 'dispatchEvent'] - .forEach(function(method) { - pc[method] = _eventTarget[method].bind(_eventTarget); - }); - - this.canTrickleIceCandidates = null; - - this.needNegotiation = false; - - this.localStreams = []; - this.remoteStreams = []; - - this._localDescription = null; - this._remoteDescription = null; - - this.signalingState = 'stable'; - this.iceConnectionState = 'new'; - this.connectionState = 'new'; - this.iceGatheringState = 'new'; - - config = JSON.parse(JSON.stringify(config || {})); - - this.usingBundle = config.bundlePolicy === 'max-bundle'; - if (config.rtcpMuxPolicy === 'negotiate') { - throw(makeError('NotSupportedError', - 'rtcpMuxPolicy \'negotiate\' is not supported')); - } else if (!config.rtcpMuxPolicy) { - config.rtcpMuxPolicy = 'require'; - } - - switch (config.iceTransportPolicy) { - case 'all': - case 'relay': - break; - default: - config.iceTransportPolicy = 'all'; - break; - } - - switch (config.bundlePolicy) { - case 'balanced': - case 'max-compat': - case 'max-bundle': - break; - default: - config.bundlePolicy = 'balanced'; - break; - } - - config.iceServers = filterIceServers(config.iceServers || [], edgeVersion); - - this._iceGatherers = []; - if (config.iceCandidatePoolSize) { - for (var i = config.iceCandidatePoolSize; i > 0; i--) { - this._iceGatherers.push(new window.RTCIceGatherer({ - iceServers: config.iceServers, - gatherPolicy: config.iceTransportPolicy - })); - } - } else { - config.iceCandidatePoolSize = 0; - } - - this._config = config; - - // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ... - // everything that is needed to describe a SDP m-line. - this.transceivers = []; - - this._sdpSessionId = SDPUtils.generateSessionId(); - this._sdpSessionVersion = 0; - - this._dtlsRole = undefined; // role for a=setup to use in answers. - - this._isClosed = false; - }; - - Object.defineProperty(RTCPeerConnection.prototype, 'localDescription', { - configurable: true, - get: function() { - return this._localDescription; - } - }); - Object.defineProperty(RTCPeerConnection.prototype, 'remoteDescription', { - configurable: true, - get: function() { - return this._remoteDescription; - } - }); - - // set up event handlers on prototype - RTCPeerConnection.prototype.onicecandidate = null; - RTCPeerConnection.prototype.onaddstream = null; - RTCPeerConnection.prototype.ontrack = null; - RTCPeerConnection.prototype.onremovestream = null; - RTCPeerConnection.prototype.onsignalingstatechange = null; - RTCPeerConnection.prototype.oniceconnectionstatechange = null; - RTCPeerConnection.prototype.onconnectionstatechange = null; - RTCPeerConnection.prototype.onicegatheringstatechange = null; - RTCPeerConnection.prototype.onnegotiationneeded = null; - RTCPeerConnection.prototype.ondatachannel = null; - - RTCPeerConnection.prototype._dispatchEvent = function(name, event) { - if (this._isClosed) { - return; - } - this.dispatchEvent(event); - if (typeof this['on' + name] === 'function') { - this['on' + name](event); - } - }; - - RTCPeerConnection.prototype._emitGatheringStateChange = function() { - var event = new Event('icegatheringstatechange'); - this._dispatchEvent('icegatheringstatechange', event); - }; - - RTCPeerConnection.prototype.getConfiguration = function() { - return this._config; - }; - - RTCPeerConnection.prototype.getLocalStreams = function() { - return this.localStreams; - }; - - RTCPeerConnection.prototype.getRemoteStreams = function() { - return this.remoteStreams; - }; - - // internal helper to create a transceiver object. - // (which is not yet the same as the WebRTC 1.0 transceiver) - RTCPeerConnection.prototype._createTransceiver = function(kind, doNotAdd) { - var hasBundleTransport = this.transceivers.length > 0; - var transceiver = { - track: null, - iceGatherer: null, - iceTransport: null, - dtlsTransport: null, - localCapabilities: null, - remoteCapabilities: null, - rtpSender: null, - rtpReceiver: null, - kind: kind, - mid: null, - sendEncodingParameters: null, - recvEncodingParameters: null, - stream: null, - associatedRemoteMediaStreams: [], - wantReceive: true - }; - if (this.usingBundle && hasBundleTransport) { - transceiver.iceTransport = this.transceivers[0].iceTransport; - transceiver.dtlsTransport = this.transceivers[0].dtlsTransport; - } else { - var transports = this._createIceAndDtlsTransports(); - transceiver.iceTransport = transports.iceTransport; - transceiver.dtlsTransport = transports.dtlsTransport; - } - if (!doNotAdd) { - this.transceivers.push(transceiver); - } - return transceiver; - }; - - RTCPeerConnection.prototype.addTrack = function(track, stream) { - if (this._isClosed) { - throw makeError('InvalidStateError', - 'Attempted to call addTrack on a closed peerconnection.'); - } - - var alreadyExists = this.transceivers.find(function(s) { - return s.track === track; - }); - - if (alreadyExists) { - throw makeError('InvalidAccessError', 'Track already exists.'); - } - - var transceiver; - for (var i = 0; i < this.transceivers.length; i++) { - if (!this.transceivers[i].track && - this.transceivers[i].kind === track.kind) { - transceiver = this.transceivers[i]; - } - } - if (!transceiver) { - transceiver = this._createTransceiver(track.kind); - } - - this._maybeFireNegotiationNeeded(); - - if (this.localStreams.indexOf(stream) === -1) { - this.localStreams.push(stream); - } - - transceiver.track = track; - transceiver.stream = stream; - transceiver.rtpSender = new window.RTCRtpSender(track, - transceiver.dtlsTransport); - return transceiver.rtpSender; - }; - - RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - if (edgeVersion >= 15025) { - stream.getTracks().forEach(function(track) { - pc.addTrack(track, stream); - }); - } else { - // Clone is necessary for local demos mostly, attaching directly - // to two different senders does not work (build 10547). - // Fixed in 15025 (or earlier) - var clonedStream = stream.clone(); - stream.getTracks().forEach(function(track, idx) { - var clonedTrack = clonedStream.getTracks()[idx]; - track.addEventListener('enabled', function(event) { - clonedTrack.enabled = event.enabled; - }); - }); - clonedStream.getTracks().forEach(function(track) { - pc.addTrack(track, clonedStream); - }); - } - }; - - RTCPeerConnection.prototype.removeTrack = function(sender) { - if (this._isClosed) { - throw makeError('InvalidStateError', - 'Attempted to call removeTrack on a closed peerconnection.'); - } - - if (!(sender instanceof window.RTCRtpSender)) { - throw new TypeError('Argument 1 of RTCPeerConnection.removeTrack ' + - 'does not implement interface RTCRtpSender.'); - } - - var transceiver = this.transceivers.find(function(t) { - return t.rtpSender === sender; - }); - - if (!transceiver) { - throw makeError('InvalidAccessError', - 'Sender was not created by this connection.'); - } - var stream = transceiver.stream; - - transceiver.rtpSender.stop(); - transceiver.rtpSender = null; - transceiver.track = null; - transceiver.stream = null; - - // remove the stream from the set of local streams - var localStreams = this.transceivers.map(function(t) { - return t.stream; - }); - if (localStreams.indexOf(stream) === -1 && - this.localStreams.indexOf(stream) > -1) { - this.localStreams.splice(this.localStreams.indexOf(stream), 1); - } - - this._maybeFireNegotiationNeeded(); - }; - - RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - stream.getTracks().forEach(function(track) { - var sender = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (sender) { - pc.removeTrack(sender); - } - }); - }; - - RTCPeerConnection.prototype.getSenders = function() { - return this.transceivers.filter(function(transceiver) { - return !!transceiver.rtpSender; - }) - .map(function(transceiver) { - return transceiver.rtpSender; - }); - }; - - RTCPeerConnection.prototype.getReceivers = function() { - return this.transceivers.filter(function(transceiver) { - return !!transceiver.rtpReceiver; - }) - .map(function(transceiver) { - return transceiver.rtpReceiver; - }); - }; - - - RTCPeerConnection.prototype._createIceGatherer = function(sdpMLineIndex, - usingBundle) { - var pc = this; - if (usingBundle && sdpMLineIndex > 0) { - return this.transceivers[0].iceGatherer; - } else if (this._iceGatherers.length) { - return this._iceGatherers.shift(); - } - var iceGatherer = new window.RTCIceGatherer({ - iceServers: this._config.iceServers, - gatherPolicy: this._config.iceTransportPolicy - }); - Object.defineProperty(iceGatherer, 'state', - {value: 'new', writable: true} - ); - - this.transceivers[sdpMLineIndex].bufferedCandidateEvents = []; - this.transceivers[sdpMLineIndex].bufferCandidates = function(event) { - var end = !event.candidate || Object.keys(event.candidate).length === 0; - // polyfill since RTCIceGatherer.state is not implemented in - // Edge 10547 yet. - iceGatherer.state = end ? 'completed' : 'gathering'; - if (pc.transceivers[sdpMLineIndex].bufferedCandidateEvents !== null) { - pc.transceivers[sdpMLineIndex].bufferedCandidateEvents.push(event); - } - }; - iceGatherer.addEventListener('localcandidate', - this.transceivers[sdpMLineIndex].bufferCandidates); - return iceGatherer; - }; - - // start gathering from an RTCIceGatherer. - RTCPeerConnection.prototype._gather = function(mid, sdpMLineIndex) { - var pc = this; - var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; - if (iceGatherer.onlocalcandidate) { - return; - } - var bufferedCandidateEvents = - this.transceivers[sdpMLineIndex].bufferedCandidateEvents; - this.transceivers[sdpMLineIndex].bufferedCandidateEvents = null; - iceGatherer.removeEventListener('localcandidate', - this.transceivers[sdpMLineIndex].bufferCandidates); - iceGatherer.onlocalcandidate = function(evt) { - if (pc.usingBundle && sdpMLineIndex > 0) { - // if we know that we use bundle we can drop candidates with - // ѕdpMLineIndex > 0. If we don't do this then our state gets - // confused since we dispose the extra ice gatherer. - return; - } - var event = new Event('icecandidate'); - event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex}; - - var cand = evt.candidate; - // Edge emits an empty object for RTCIceCandidateComplete‥ - var end = !cand || Object.keys(cand).length === 0; - if (end) { - // polyfill since RTCIceGatherer.state is not implemented in - // Edge 10547 yet. - if (iceGatherer.state === 'new' || iceGatherer.state === 'gathering') { - iceGatherer.state = 'completed'; - } - } else { - if (iceGatherer.state === 'new') { - iceGatherer.state = 'gathering'; - } - // RTCIceCandidate doesn't have a component, needs to be added - cand.component = 1; - // also the usernameFragment. TODO: update SDP to take both variants. - cand.ufrag = iceGatherer.getLocalParameters().usernameFragment; - - var serializedCandidate = SDPUtils.writeCandidate(cand); - event.candidate = Object.assign(event.candidate, - SDPUtils.parseCandidate(serializedCandidate)); - - event.candidate.candidate = serializedCandidate; - event.candidate.toJSON = function() { - return { - candidate: event.candidate.candidate, - sdpMid: event.candidate.sdpMid, - sdpMLineIndex: event.candidate.sdpMLineIndex, - usernameFragment: event.candidate.usernameFragment - }; - }; - } - - // update local description. - var sections = SDPUtils.getMediaSections(pc._localDescription.sdp); - if (!end) { - sections[event.candidate.sdpMLineIndex] += - 'a=' + event.candidate.candidate + '\r\n'; - } else { - sections[event.candidate.sdpMLineIndex] += - 'a=end-of-candidates\r\n'; - } - pc._localDescription.sdp = - SDPUtils.getDescription(pc._localDescription.sdp) + - sections.join(''); - var complete = pc.transceivers.every(function(transceiver) { - return transceiver.iceGatherer && - transceiver.iceGatherer.state === 'completed'; - }); - - if (pc.iceGatheringState !== 'gathering') { - pc.iceGatheringState = 'gathering'; - pc._emitGatheringStateChange(); - } - - // Emit candidate. Also emit null candidate when all gatherers are - // complete. - if (!end) { - pc._dispatchEvent('icecandidate', event); - } - if (complete) { - pc._dispatchEvent('icecandidate', new Event('icecandidate')); - pc.iceGatheringState = 'complete'; - pc._emitGatheringStateChange(); - } - }; - - // emit already gathered candidates. - window.setTimeout(function() { - bufferedCandidateEvents.forEach(function(e) { - iceGatherer.onlocalcandidate(e); - }); - }, 0); - }; - - // Create ICE transport and DTLS transport. - RTCPeerConnection.prototype._createIceAndDtlsTransports = function() { - var pc = this; - var iceTransport = new window.RTCIceTransport(null); - iceTransport.onicestatechange = function() { - pc._updateIceConnectionState(); - pc._updateConnectionState(); - }; - - var dtlsTransport = new window.RTCDtlsTransport(iceTransport); - dtlsTransport.ondtlsstatechange = function() { - pc._updateConnectionState(); - }; - dtlsTransport.onerror = function() { - // onerror does not set state to failed by itself. - Object.defineProperty(dtlsTransport, 'state', - {value: 'failed', writable: true}); - pc._updateConnectionState(); - }; - - return { - iceTransport: iceTransport, - dtlsTransport: dtlsTransport - }; - }; - - // Destroy ICE gatherer, ICE transport and DTLS transport. - // Without triggering the callbacks. - RTCPeerConnection.prototype._disposeIceAndDtlsTransports = function( - sdpMLineIndex) { - var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; - if (iceGatherer) { - delete iceGatherer.onlocalcandidate; - delete this.transceivers[sdpMLineIndex].iceGatherer; - } - var iceTransport = this.transceivers[sdpMLineIndex].iceTransport; - if (iceTransport) { - delete iceTransport.onicestatechange; - delete this.transceivers[sdpMLineIndex].iceTransport; - } - var dtlsTransport = this.transceivers[sdpMLineIndex].dtlsTransport; - if (dtlsTransport) { - delete dtlsTransport.ondtlsstatechange; - delete dtlsTransport.onerror; - delete this.transceivers[sdpMLineIndex].dtlsTransport; - } - }; - - // Start the RTP Sender and Receiver for a transceiver. - RTCPeerConnection.prototype._transceive = function(transceiver, - send, recv) { - var params = getCommonCapabilities(transceiver.localCapabilities, - transceiver.remoteCapabilities); - if (send && transceiver.rtpSender) { - params.encodings = transceiver.sendEncodingParameters; - params.rtcp = { - cname: SDPUtils.localCName, - compound: transceiver.rtcpParameters.compound - }; - if (transceiver.recvEncodingParameters.length) { - params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc; - } - transceiver.rtpSender.send(params); - } - if (recv && transceiver.rtpReceiver && params.codecs.length > 0) { - // remove RTX field in Edge 14942 - if (transceiver.kind === 'video' - && transceiver.recvEncodingParameters - && edgeVersion < 15019) { - transceiver.recvEncodingParameters.forEach(function(p) { - delete p.rtx; - }); - } - if (transceiver.recvEncodingParameters.length) { - params.encodings = transceiver.recvEncodingParameters; - } else { - params.encodings = [{}]; - } - params.rtcp = { - compound: transceiver.rtcpParameters.compound - }; - if (transceiver.rtcpParameters.cname) { - params.rtcp.cname = transceiver.rtcpParameters.cname; - } - if (transceiver.sendEncodingParameters.length) { - params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc; - } - transceiver.rtpReceiver.receive(params); - } - }; - - RTCPeerConnection.prototype.setLocalDescription = function(description) { - var pc = this; - - // Note: pranswer is not supported. - if (['offer', 'answer'].indexOf(description.type) === -1) { - return Promise.reject(makeError('TypeError', - 'Unsupported type "' + description.type + '"')); - } - - if (!isActionAllowedInSignalingState('setLocalDescription', - description.type, pc.signalingState) || pc._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not set local ' + description.type + - ' in state ' + pc.signalingState)); - } - - var sections; - var sessionpart; - if (description.type === 'offer') { - // VERY limited support for SDP munging. Limited to: - // * changing the order of codecs - sections = SDPUtils.splitSections(description.sdp); - sessionpart = sections.shift(); - sections.forEach(function(mediaSection, sdpMLineIndex) { - var caps = SDPUtils.parseRtpParameters(mediaSection); - pc.transceivers[sdpMLineIndex].localCapabilities = caps; - }); - - pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { - pc._gather(transceiver.mid, sdpMLineIndex); - }); - } else if (description.type === 'answer') { - sections = SDPUtils.splitSections(pc._remoteDescription.sdp); - sessionpart = sections.shift(); - var isIceLite = SDPUtils.matchPrefix(sessionpart, - 'a=ice-lite').length > 0; - sections.forEach(function(mediaSection, sdpMLineIndex) { - var transceiver = pc.transceivers[sdpMLineIndex]; - var iceGatherer = transceiver.iceGatherer; - var iceTransport = transceiver.iceTransport; - var dtlsTransport = transceiver.dtlsTransport; - var localCapabilities = transceiver.localCapabilities; - var remoteCapabilities = transceiver.remoteCapabilities; - - // treat bundle-only as not-rejected. - var rejected = SDPUtils.isRejected(mediaSection) && - SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0; - - if (!rejected && !transceiver.rejected) { - var remoteIceParameters = SDPUtils.getIceParameters( - mediaSection, sessionpart); - var remoteDtlsParameters = SDPUtils.getDtlsParameters( - mediaSection, sessionpart); - if (isIceLite) { - remoteDtlsParameters.role = 'server'; - } - - if (!pc.usingBundle || sdpMLineIndex === 0) { - pc._gather(transceiver.mid, sdpMLineIndex); - if (iceTransport.state === 'new') { - iceTransport.start(iceGatherer, remoteIceParameters, - isIceLite ? 'controlling' : 'controlled'); - } - if (dtlsTransport.state === 'new') { - dtlsTransport.start(remoteDtlsParameters); - } - } - - // Calculate intersection of capabilities. - var params = getCommonCapabilities(localCapabilities, - remoteCapabilities); - - // Start the RTCRtpSender. The RTCRtpReceiver for this - // transceiver has already been started in setRemoteDescription. - pc._transceive(transceiver, - params.codecs.length > 0, - false); - } - }); - } - - pc._localDescription = { - type: description.type, - sdp: description.sdp - }; - if (description.type === 'offer') { - pc._updateSignalingState('have-local-offer'); - } else { - pc._updateSignalingState('stable'); - } - - return Promise.resolve(); - }; - - RTCPeerConnection.prototype.setRemoteDescription = function(description) { - var pc = this; - - // Note: pranswer is not supported. - if (['offer', 'answer'].indexOf(description.type) === -1) { - return Promise.reject(makeError('TypeError', - 'Unsupported type "' + description.type + '"')); - } - - if (!isActionAllowedInSignalingState('setRemoteDescription', - description.type, pc.signalingState) || pc._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not set remote ' + description.type + - ' in state ' + pc.signalingState)); - } - - var streams = {}; - pc.remoteStreams.forEach(function(stream) { - streams[stream.id] = stream; - }); - var receiverList = []; - var sections = SDPUtils.splitSections(description.sdp); - var sessionpart = sections.shift(); - var isIceLite = SDPUtils.matchPrefix(sessionpart, - 'a=ice-lite').length > 0; - var usingBundle = SDPUtils.matchPrefix(sessionpart, - 'a=group:BUNDLE ').length > 0; - pc.usingBundle = usingBundle; - var iceOptions = SDPUtils.matchPrefix(sessionpart, - 'a=ice-options:')[0]; - if (iceOptions) { - pc.canTrickleIceCandidates = iceOptions.substr(14).split(' ') - .indexOf('trickle') >= 0; - } else { - pc.canTrickleIceCandidates = false; - } - - sections.forEach(function(mediaSection, sdpMLineIndex) { - var lines = SDPUtils.splitLines(mediaSection); - var kind = SDPUtils.getKind(mediaSection); - // treat bundle-only as not-rejected. - var rejected = SDPUtils.isRejected(mediaSection) && - SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0; - var protocol = lines[0].substr(2).split(' ')[2]; - - var direction = SDPUtils.getDirection(mediaSection, sessionpart); - var remoteMsid = SDPUtils.parseMsid(mediaSection); - - var mid = SDPUtils.getMid(mediaSection) || SDPUtils.generateIdentifier(); - - // Reject datachannels which are not implemented yet. - if (rejected || (kind === 'application' && (protocol === 'DTLS/SCTP' || - protocol === 'UDP/DTLS/SCTP'))) { - // TODO: this is dangerous in the case where a non-rejected m-line - // becomes rejected. - pc.transceivers[sdpMLineIndex] = { - mid: mid, - kind: kind, - protocol: protocol, - rejected: true - }; - return; - } - - if (!rejected && pc.transceivers[sdpMLineIndex] && - pc.transceivers[sdpMLineIndex].rejected) { - // recycle a rejected transceiver. - pc.transceivers[sdpMLineIndex] = pc._createTransceiver(kind, true); - } - - var transceiver; - var iceGatherer; - var iceTransport; - var dtlsTransport; - var rtpReceiver; - var sendEncodingParameters; - var recvEncodingParameters; - var localCapabilities; - - var track; - // FIXME: ensure the mediaSection has rtcp-mux set. - var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection); - var remoteIceParameters; - var remoteDtlsParameters; - if (!rejected) { - remoteIceParameters = SDPUtils.getIceParameters(mediaSection, - sessionpart); - remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection, - sessionpart); - remoteDtlsParameters.role = 'client'; - } - recvEncodingParameters = - SDPUtils.parseRtpEncodingParameters(mediaSection); - - var rtcpParameters = SDPUtils.parseRtcpParameters(mediaSection); - - var isComplete = SDPUtils.matchPrefix(mediaSection, - 'a=end-of-candidates', sessionpart).length > 0; - var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:') - .map(function(cand) { - return SDPUtils.parseCandidate(cand); - }) - .filter(function(cand) { - return cand.component === 1; - }); - - // Check if we can use BUNDLE and dispose transports. - if ((description.type === 'offer' || description.type === 'answer') && - !rejected && usingBundle && sdpMLineIndex > 0 && - pc.transceivers[sdpMLineIndex]) { - pc._disposeIceAndDtlsTransports(sdpMLineIndex); - pc.transceivers[sdpMLineIndex].iceGatherer = - pc.transceivers[0].iceGatherer; - pc.transceivers[sdpMLineIndex].iceTransport = - pc.transceivers[0].iceTransport; - pc.transceivers[sdpMLineIndex].dtlsTransport = - pc.transceivers[0].dtlsTransport; - if (pc.transceivers[sdpMLineIndex].rtpSender) { - pc.transceivers[sdpMLineIndex].rtpSender.setTransport( - pc.transceivers[0].dtlsTransport); - } - if (pc.transceivers[sdpMLineIndex].rtpReceiver) { - pc.transceivers[sdpMLineIndex].rtpReceiver.setTransport( - pc.transceivers[0].dtlsTransport); - } - } - if (description.type === 'offer' && !rejected) { - transceiver = pc.transceivers[sdpMLineIndex] || - pc._createTransceiver(kind); - transceiver.mid = mid; - - if (!transceiver.iceGatherer) { - transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex, - usingBundle); - } - - if (cands.length && transceiver.iceTransport.state === 'new') { - if (isComplete && (!usingBundle || sdpMLineIndex === 0)) { - transceiver.iceTransport.setRemoteCandidates(cands); - } else { - cands.forEach(function(candidate) { - maybeAddCandidate(transceiver.iceTransport, candidate); - }); - } - } - - localCapabilities = window.RTCRtpReceiver.getCapabilities(kind); - - // filter RTX until additional stuff needed for RTX is implemented - // in adapter.js - if (edgeVersion < 15019) { - localCapabilities.codecs = localCapabilities.codecs.filter( - function(codec) { - return codec.name !== 'rtx'; - }); - } - - sendEncodingParameters = transceiver.sendEncodingParameters || [{ - ssrc: (2 * sdpMLineIndex + 2) * 1001 - }]; - - // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams - var isNewTrack = false; - if (direction === 'sendrecv' || direction === 'sendonly') { - isNewTrack = !transceiver.rtpReceiver; - rtpReceiver = transceiver.rtpReceiver || - new window.RTCRtpReceiver(transceiver.dtlsTransport, kind); - - if (isNewTrack) { - var stream; - track = rtpReceiver.track; - // FIXME: does not work with Plan B. - if (remoteMsid && remoteMsid.stream === '-') { - // no-op. a stream id of '-' means: no associated stream. - } else if (remoteMsid) { - if (!streams[remoteMsid.stream]) { - streams[remoteMsid.stream] = new window.MediaStream(); - Object.defineProperty(streams[remoteMsid.stream], 'id', { - get: function() { - return remoteMsid.stream; - } - }); - } - Object.defineProperty(track, 'id', { - get: function() { - return remoteMsid.track; - } - }); - stream = streams[remoteMsid.stream]; - } else { - if (!streams.default) { - streams.default = new window.MediaStream(); - } - stream = streams.default; - } - if (stream) { - addTrackToStreamAndFireEvent(track, stream); - transceiver.associatedRemoteMediaStreams.push(stream); - } - receiverList.push([track, rtpReceiver, stream]); - } - } else if (transceiver.rtpReceiver && transceiver.rtpReceiver.track) { - transceiver.associatedRemoteMediaStreams.forEach(function(s) { - var nativeTrack = s.getTracks().find(function(t) { - return t.id === transceiver.rtpReceiver.track.id; - }); - if (nativeTrack) { - removeTrackFromStreamAndFireEvent(nativeTrack, s); - } - }); - transceiver.associatedRemoteMediaStreams = []; - } - - transceiver.localCapabilities = localCapabilities; - transceiver.remoteCapabilities = remoteCapabilities; - transceiver.rtpReceiver = rtpReceiver; - transceiver.rtcpParameters = rtcpParameters; - transceiver.sendEncodingParameters = sendEncodingParameters; - transceiver.recvEncodingParameters = recvEncodingParameters; - - // Start the RTCRtpReceiver now. The RTPSender is started in - // setLocalDescription. - pc._transceive(pc.transceivers[sdpMLineIndex], - false, - isNewTrack); - } else if (description.type === 'answer' && !rejected) { - transceiver = pc.transceivers[sdpMLineIndex]; - iceGatherer = transceiver.iceGatherer; - iceTransport = transceiver.iceTransport; - dtlsTransport = transceiver.dtlsTransport; - rtpReceiver = transceiver.rtpReceiver; - sendEncodingParameters = transceiver.sendEncodingParameters; - localCapabilities = transceiver.localCapabilities; - - pc.transceivers[sdpMLineIndex].recvEncodingParameters = - recvEncodingParameters; - pc.transceivers[sdpMLineIndex].remoteCapabilities = - remoteCapabilities; - pc.transceivers[sdpMLineIndex].rtcpParameters = rtcpParameters; - - if (cands.length && iceTransport.state === 'new') { - if ((isIceLite || isComplete) && - (!usingBundle || sdpMLineIndex === 0)) { - iceTransport.setRemoteCandidates(cands); - } else { - cands.forEach(function(candidate) { - maybeAddCandidate(transceiver.iceTransport, candidate); - }); - } - } - - if (!usingBundle || sdpMLineIndex === 0) { - if (iceTransport.state === 'new') { - iceTransport.start(iceGatherer, remoteIceParameters, - 'controlling'); - } - if (dtlsTransport.state === 'new') { - dtlsTransport.start(remoteDtlsParameters); - } - } - - // If the offer contained RTX but the answer did not, - // remove RTX from sendEncodingParameters. - var commonCapabilities = getCommonCapabilities( - transceiver.localCapabilities, - transceiver.remoteCapabilities); - - var hasRtx = commonCapabilities.codecs.filter(function(c) { - return c.name.toLowerCase() === 'rtx'; - }).length; - if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) { - delete transceiver.sendEncodingParameters[0].rtx; - } - - pc._transceive(transceiver, - direction === 'sendrecv' || direction === 'recvonly', - direction === 'sendrecv' || direction === 'sendonly'); - - // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams - if (rtpReceiver && - (direction === 'sendrecv' || direction === 'sendonly')) { - track = rtpReceiver.track; - if (remoteMsid) { - if (!streams[remoteMsid.stream]) { - streams[remoteMsid.stream] = new window.MediaStream(); - } - addTrackToStreamAndFireEvent(track, streams[remoteMsid.stream]); - receiverList.push([track, rtpReceiver, streams[remoteMsid.stream]]); - } else { - if (!streams.default) { - streams.default = new window.MediaStream(); - } - addTrackToStreamAndFireEvent(track, streams.default); - receiverList.push([track, rtpReceiver, streams.default]); - } - } else { - // FIXME: actually the receiver should be created later. - delete transceiver.rtpReceiver; - } - } - }); - - if (pc._dtlsRole === undefined) { - pc._dtlsRole = description.type === 'offer' ? 'active' : 'passive'; - } - - pc._remoteDescription = { - type: description.type, - sdp: description.sdp - }; - if (description.type === 'offer') { - pc._updateSignalingState('have-remote-offer'); - } else { - pc._updateSignalingState('stable'); - } - Object.keys(streams).forEach(function(sid) { - var stream = streams[sid]; - if (stream.getTracks().length) { - if (pc.remoteStreams.indexOf(stream) === -1) { - pc.remoteStreams.push(stream); - var event = new Event('addstream'); - event.stream = stream; - window.setTimeout(function() { - pc._dispatchEvent('addstream', event); - }); - } - - receiverList.forEach(function(item) { - var track = item[0]; - var receiver = item[1]; - if (stream.id !== item[2].id) { - return; - } - fireAddTrack(pc, track, receiver, [stream]); - }); - } - }); - receiverList.forEach(function(item) { - if (item[2]) { - return; - } - fireAddTrack(pc, item[0], item[1], []); - }); - - // check whether addIceCandidate({}) was called within four seconds after - // setRemoteDescription. - window.setTimeout(function() { - if (!(pc && pc.transceivers)) { - return; - } - pc.transceivers.forEach(function(transceiver) { - if (transceiver.iceTransport && - transceiver.iceTransport.state === 'new' && - transceiver.iceTransport.getRemoteCandidates().length > 0) { - console.warn('Timeout for addRemoteCandidate. Consider sending ' + - 'an end-of-candidates notification'); - transceiver.iceTransport.addRemoteCandidate({}); - } - }); - }, 4000); - - return Promise.resolve(); - }; - - RTCPeerConnection.prototype.close = function() { - this.transceivers.forEach(function(transceiver) { - /* not yet - if (transceiver.iceGatherer) { - transceiver.iceGatherer.close(); - } - */ - if (transceiver.iceTransport) { - transceiver.iceTransport.stop(); - } - if (transceiver.dtlsTransport) { - transceiver.dtlsTransport.stop(); - } - if (transceiver.rtpSender) { - transceiver.rtpSender.stop(); - } - if (transceiver.rtpReceiver) { - transceiver.rtpReceiver.stop(); - } - }); - // FIXME: clean up tracks, local streams, remote streams, etc - this._isClosed = true; - this._updateSignalingState('closed'); - }; - - // Update the signaling state. - RTCPeerConnection.prototype._updateSignalingState = function(newState) { - this.signalingState = newState; - var event = new Event('signalingstatechange'); - this._dispatchEvent('signalingstatechange', event); - }; - - // Determine whether to fire the negotiationneeded event. - RTCPeerConnection.prototype._maybeFireNegotiationNeeded = function() { - var pc = this; - if (this.signalingState !== 'stable' || this.needNegotiation === true) { - return; - } - this.needNegotiation = true; - window.setTimeout(function() { - if (pc.needNegotiation) { - pc.needNegotiation = false; - var event = new Event('negotiationneeded'); - pc._dispatchEvent('negotiationneeded', event); - } - }, 0); - }; - - // Update the ice connection state. - RTCPeerConnection.prototype._updateIceConnectionState = function() { - var newState; - var states = { - 'new': 0, - closed: 0, - checking: 0, - connected: 0, - completed: 0, - disconnected: 0, - failed: 0 - }; - this.transceivers.forEach(function(transceiver) { - if (transceiver.iceTransport && !transceiver.rejected) { - states[transceiver.iceTransport.state]++; - } - }); - - newState = 'new'; - if (states.failed > 0) { - newState = 'failed'; - } else if (states.checking > 0) { - newState = 'checking'; - } else if (states.disconnected > 0) { - newState = 'disconnected'; - } else if (states.new > 0) { - newState = 'new'; - } else if (states.connected > 0) { - newState = 'connected'; - } else if (states.completed > 0) { - newState = 'completed'; - } - - if (newState !== this.iceConnectionState) { - this.iceConnectionState = newState; - var event = new Event('iceconnectionstatechange'); - this._dispatchEvent('iceconnectionstatechange', event); - } - }; - - // Update the connection state. - RTCPeerConnection.prototype._updateConnectionState = function() { - var newState; - var states = { - 'new': 0, - closed: 0, - connecting: 0, - connected: 0, - completed: 0, - disconnected: 0, - failed: 0 - }; - this.transceivers.forEach(function(transceiver) { - if (transceiver.iceTransport && transceiver.dtlsTransport && - !transceiver.rejected) { - states[transceiver.iceTransport.state]++; - states[transceiver.dtlsTransport.state]++; - } - }); - // ICETransport.completed and connected are the same for this purpose. - states.connected += states.completed; - - newState = 'new'; - if (states.failed > 0) { - newState = 'failed'; - } else if (states.connecting > 0) { - newState = 'connecting'; - } else if (states.disconnected > 0) { - newState = 'disconnected'; - } else if (states.new > 0) { - newState = 'new'; - } else if (states.connected > 0) { - newState = 'connected'; - } - - if (newState !== this.connectionState) { - this.connectionState = newState; - var event = new Event('connectionstatechange'); - this._dispatchEvent('connectionstatechange', event); - } - }; - - RTCPeerConnection.prototype.createOffer = function() { - var pc = this; - - if (pc._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not call createOffer after close')); - } - - var numAudioTracks = pc.transceivers.filter(function(t) { - return t.kind === 'audio'; - }).length; - var numVideoTracks = pc.transceivers.filter(function(t) { - return t.kind === 'video'; - }).length; - - // Determine number of audio and video tracks we need to send/recv. - var offerOptions = arguments[0]; - if (offerOptions) { - // Reject Chrome legacy constraints. - if (offerOptions.mandatory || offerOptions.optional) { - throw new TypeError( - 'Legacy mandatory/optional constraints not supported.'); - } - if (offerOptions.offerToReceiveAudio !== undefined) { - if (offerOptions.offerToReceiveAudio === true) { - numAudioTracks = 1; - } else if (offerOptions.offerToReceiveAudio === false) { - numAudioTracks = 0; - } else { - numAudioTracks = offerOptions.offerToReceiveAudio; - } - } - if (offerOptions.offerToReceiveVideo !== undefined) { - if (offerOptions.offerToReceiveVideo === true) { - numVideoTracks = 1; - } else if (offerOptions.offerToReceiveVideo === false) { - numVideoTracks = 0; - } else { - numVideoTracks = offerOptions.offerToReceiveVideo; - } - } - } - - pc.transceivers.forEach(function(transceiver) { - if (transceiver.kind === 'audio') { - numAudioTracks--; - if (numAudioTracks < 0) { - transceiver.wantReceive = false; - } - } else if (transceiver.kind === 'video') { - numVideoTracks--; - if (numVideoTracks < 0) { - transceiver.wantReceive = false; - } - } - }); - - // Create M-lines for recvonly streams. - while (numAudioTracks > 0 || numVideoTracks > 0) { - if (numAudioTracks > 0) { - pc._createTransceiver('audio'); - numAudioTracks--; - } - if (numVideoTracks > 0) { - pc._createTransceiver('video'); - numVideoTracks--; - } - } - - var sdp = SDPUtils.writeSessionBoilerplate(pc._sdpSessionId, - pc._sdpSessionVersion++); - pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { - // For each track, create an ice gatherer, ice transport, - // dtls transport, potentially rtpsender and rtpreceiver. - var track = transceiver.track; - var kind = transceiver.kind; - var mid = transceiver.mid || SDPUtils.generateIdentifier(); - transceiver.mid = mid; - - if (!transceiver.iceGatherer) { - transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex, - pc.usingBundle); - } - - var localCapabilities = window.RTCRtpSender.getCapabilities(kind); - // filter RTX until additional stuff needed for RTX is implemented - // in adapter.js - if (edgeVersion < 15019) { - localCapabilities.codecs = localCapabilities.codecs.filter( - function(codec) { - return codec.name !== 'rtx'; - }); - } - localCapabilities.codecs.forEach(function(codec) { - // work around https://bugs.chromium.org/p/webrtc/issues/detail?id=6552 - // by adding level-asymmetry-allowed=1 - if (codec.name === 'H264' && - codec.parameters['level-asymmetry-allowed'] === undefined) { - codec.parameters['level-asymmetry-allowed'] = '1'; - } - - // for subsequent offers, we might have to re-use the payload - // type of the last offer. - if (transceiver.remoteCapabilities && - transceiver.remoteCapabilities.codecs) { - transceiver.remoteCapabilities.codecs.forEach(function(remoteCodec) { - if (codec.name.toLowerCase() === remoteCodec.name.toLowerCase() && - codec.clockRate === remoteCodec.clockRate) { - codec.preferredPayloadType = remoteCodec.payloadType; - } - }); - } - }); - localCapabilities.headerExtensions.forEach(function(hdrExt) { - var remoteExtensions = transceiver.remoteCapabilities && - transceiver.remoteCapabilities.headerExtensions || []; - remoteExtensions.forEach(function(rHdrExt) { - if (hdrExt.uri === rHdrExt.uri) { - hdrExt.id = rHdrExt.id; - } - }); - }); - - // generate an ssrc now, to be used later in rtpSender.send - var sendEncodingParameters = transceiver.sendEncodingParameters || [{ - ssrc: (2 * sdpMLineIndex + 1) * 1001 - }]; - if (track) { - // add RTX - if (edgeVersion >= 15019 && kind === 'video' && - !sendEncodingParameters[0].rtx) { - sendEncodingParameters[0].rtx = { - ssrc: sendEncodingParameters[0].ssrc + 1 - }; - } - } - - if (transceiver.wantReceive) { - transceiver.rtpReceiver = new window.RTCRtpReceiver( - transceiver.dtlsTransport, kind); - } - - transceiver.localCapabilities = localCapabilities; - transceiver.sendEncodingParameters = sendEncodingParameters; - }); - - // always offer BUNDLE and dispose on return if not supported. - if (pc._config.bundlePolicy !== 'max-compat') { - sdp += 'a=group:BUNDLE ' + pc.transceivers.map(function(t) { - return t.mid; - }).join(' ') + '\r\n'; - } - sdp += 'a=ice-options:trickle\r\n'; - - pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { - sdp += writeMediaSection(transceiver, transceiver.localCapabilities, - 'offer', transceiver.stream, pc._dtlsRole); - sdp += 'a=rtcp-rsize\r\n'; - - if (transceiver.iceGatherer && pc.iceGatheringState !== 'new' && - (sdpMLineIndex === 0 || !pc.usingBundle)) { - transceiver.iceGatherer.getLocalCandidates().forEach(function(cand) { - cand.component = 1; - sdp += 'a=' + SDPUtils.writeCandidate(cand) + '\r\n'; - }); - - if (transceiver.iceGatherer.state === 'completed') { - sdp += 'a=end-of-candidates\r\n'; - } - } - }); - - var desc = new window.RTCSessionDescription({ - type: 'offer', - sdp: sdp - }); - return Promise.resolve(desc); - }; - - RTCPeerConnection.prototype.createAnswer = function() { - var pc = this; - - if (pc._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not call createAnswer after close')); - } - - if (!(pc.signalingState === 'have-remote-offer' || - pc.signalingState === 'have-local-pranswer')) { - return Promise.reject(makeError('InvalidStateError', - 'Can not call createAnswer in signalingState ' + pc.signalingState)); - } - - var sdp = SDPUtils.writeSessionBoilerplate(pc._sdpSessionId, - pc._sdpSessionVersion++); - if (pc.usingBundle) { - sdp += 'a=group:BUNDLE ' + pc.transceivers.map(function(t) { - return t.mid; - }).join(' ') + '\r\n'; - } - sdp += 'a=ice-options:trickle\r\n'; - - var mediaSectionsInOffer = SDPUtils.getMediaSections( - pc._remoteDescription.sdp).length; - pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { - if (sdpMLineIndex + 1 > mediaSectionsInOffer) { - return; - } - if (transceiver.rejected) { - if (transceiver.kind === 'application') { - if (transceiver.protocol === 'DTLS/SCTP') { // legacy fmt - sdp += 'm=application 0 DTLS/SCTP 5000\r\n'; - } else { - sdp += 'm=application 0 ' + transceiver.protocol + - ' webrtc-datachannel\r\n'; - } - } else if (transceiver.kind === 'audio') { - sdp += 'm=audio 0 UDP/TLS/RTP/SAVPF 0\r\n' + - 'a=rtpmap:0 PCMU/8000\r\n'; - } else if (transceiver.kind === 'video') { - sdp += 'm=video 0 UDP/TLS/RTP/SAVPF 120\r\n' + - 'a=rtpmap:120 VP8/90000\r\n'; - } - sdp += 'c=IN IP4 0.0.0.0\r\n' + - 'a=inactive\r\n' + - 'a=mid:' + transceiver.mid + '\r\n'; - return; - } - - // FIXME: look at direction. - if (transceiver.stream) { - var localTrack; - if (transceiver.kind === 'audio') { - localTrack = transceiver.stream.getAudioTracks()[0]; - } else if (transceiver.kind === 'video') { - localTrack = transceiver.stream.getVideoTracks()[0]; - } - if (localTrack) { - // add RTX - if (edgeVersion >= 15019 && transceiver.kind === 'video' && - !transceiver.sendEncodingParameters[0].rtx) { - transceiver.sendEncodingParameters[0].rtx = { - ssrc: transceiver.sendEncodingParameters[0].ssrc + 1 - }; - } - } - } - - // Calculate intersection of capabilities. - var commonCapabilities = getCommonCapabilities( - transceiver.localCapabilities, - transceiver.remoteCapabilities); - - var hasRtx = commonCapabilities.codecs.filter(function(c) { - return c.name.toLowerCase() === 'rtx'; - }).length; - if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) { - delete transceiver.sendEncodingParameters[0].rtx; - } - - sdp += writeMediaSection(transceiver, commonCapabilities, - 'answer', transceiver.stream, pc._dtlsRole); - if (transceiver.rtcpParameters && - transceiver.rtcpParameters.reducedSize) { - sdp += 'a=rtcp-rsize\r\n'; - } - }); - - var desc = new window.RTCSessionDescription({ - type: 'answer', - sdp: sdp - }); - return Promise.resolve(desc); - }; - - RTCPeerConnection.prototype.addIceCandidate = function(candidate) { - var pc = this; - var sections; - if (candidate && !(candidate.sdpMLineIndex !== undefined || - candidate.sdpMid)) { - return Promise.reject(new TypeError('sdpMLineIndex or sdpMid required')); - } - - // TODO: needs to go into ops queue. - return new Promise(function(resolve, reject) { - if (!pc._remoteDescription) { - return reject(makeError('InvalidStateError', - 'Can not add ICE candidate without a remote description')); - } else if (!candidate || candidate.candidate === '') { - for (var j = 0; j < pc.transceivers.length; j++) { - if (pc.transceivers[j].rejected) { - continue; - } - pc.transceivers[j].iceTransport.addRemoteCandidate({}); - sections = SDPUtils.getMediaSections(pc._remoteDescription.sdp); - sections[j] += 'a=end-of-candidates\r\n'; - pc._remoteDescription.sdp = - SDPUtils.getDescription(pc._remoteDescription.sdp) + - sections.join(''); - if (pc.usingBundle) { - break; - } - } - } else { - var sdpMLineIndex = candidate.sdpMLineIndex; - if (candidate.sdpMid) { - for (var i = 0; i < pc.transceivers.length; i++) { - if (pc.transceivers[i].mid === candidate.sdpMid) { - sdpMLineIndex = i; - break; - } - } - } - var transceiver = pc.transceivers[sdpMLineIndex]; - if (transceiver) { - if (transceiver.rejected) { - return resolve(); - } - var cand = Object.keys(candidate.candidate).length > 0 ? - SDPUtils.parseCandidate(candidate.candidate) : {}; - // Ignore Chrome's invalid candidates since Edge does not like them. - if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) { - return resolve(); - } - // Ignore RTCP candidates, we assume RTCP-MUX. - if (cand.component && cand.component !== 1) { - return resolve(); - } - // when using bundle, avoid adding candidates to the wrong - // ice transport. And avoid adding candidates added in the SDP. - if (sdpMLineIndex === 0 || (sdpMLineIndex > 0 && - transceiver.iceTransport !== pc.transceivers[0].iceTransport)) { - if (!maybeAddCandidate(transceiver.iceTransport, cand)) { - return reject(makeError('OperationError', - 'Can not add ICE candidate')); - } - } - - // update the remoteDescription. - var candidateString = candidate.candidate.trim(); - if (candidateString.indexOf('a=') === 0) { - candidateString = candidateString.substr(2); - } - sections = SDPUtils.getMediaSections(pc._remoteDescription.sdp); - sections[sdpMLineIndex] += 'a=' + - (cand.type ? candidateString : 'end-of-candidates') - + '\r\n'; - pc._remoteDescription.sdp = - SDPUtils.getDescription(pc._remoteDescription.sdp) + - sections.join(''); - } else { - return reject(makeError('OperationError', - 'Can not add ICE candidate')); - } - } - resolve(); - }); - }; - - RTCPeerConnection.prototype.getStats = function(selector) { - if (selector && selector instanceof window.MediaStreamTrack) { - var senderOrReceiver = null; - this.transceivers.forEach(function(transceiver) { - if (transceiver.rtpSender && - transceiver.rtpSender.track === selector) { - senderOrReceiver = transceiver.rtpSender; - } else if (transceiver.rtpReceiver && - transceiver.rtpReceiver.track === selector) { - senderOrReceiver = transceiver.rtpReceiver; - } - }); - if (!senderOrReceiver) { - throw makeError('InvalidAccessError', 'Invalid selector.'); - } - return senderOrReceiver.getStats(); - } - - var promises = []; - this.transceivers.forEach(function(transceiver) { - ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport', - 'dtlsTransport'].forEach(function(method) { - if (transceiver[method]) { - promises.push(transceiver[method].getStats()); - } - }); - }); - return Promise.all(promises).then(function(allStats) { - var results = new Map(); - allStats.forEach(function(stats) { - stats.forEach(function(stat) { - results.set(stat.id, stat); - }); - }); - return results; - }); - }; - - // fix low-level stat names and return Map instead of object. - var ortcObjects = ['RTCRtpSender', 'RTCRtpReceiver', 'RTCIceGatherer', - 'RTCIceTransport', 'RTCDtlsTransport']; - ortcObjects.forEach(function(ortcObjectName) { - var obj = window[ortcObjectName]; - if (obj && obj.prototype && obj.prototype.getStats) { - var nativeGetstats = obj.prototype.getStats; - obj.prototype.getStats = function() { - return nativeGetstats.apply(this) - .then(function(nativeStats) { - var mapStats = new Map(); - Object.keys(nativeStats).forEach(function(id) { - nativeStats[id].type = fixStatsType(nativeStats[id]); - mapStats.set(id, nativeStats[id]); - }); - return mapStats; - }); - }; - } - }); - - // legacy callback shims. Should be moved to adapter.js some days. - var methods = ['createOffer', 'createAnswer']; - methods.forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { - var args = arguments; - if (typeof args[0] === 'function' || - typeof args[1] === 'function') { // legacy - return nativeMethod.apply(this, [arguments[2]]) - .then(function(description) { - if (typeof args[0] === 'function') { - args[0].apply(null, [description]); - } - }, function(error) { - if (typeof args[1] === 'function') { - args[1].apply(null, [error]); - } - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - - methods = ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']; - methods.forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { - var args = arguments; - if (typeof args[1] === 'function' || - typeof args[2] === 'function') { // legacy - return nativeMethod.apply(this, arguments) - .then(function() { - if (typeof args[1] === 'function') { - args[1].apply(null); - } - }, function(error) { - if (typeof args[2] === 'function') { - args[2].apply(null, [error]); - } - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - - // getStats is special. It doesn't have a spec legacy method yet we support - // getStats(something, cb) without error callbacks. - ['getStats'].forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { - var args = arguments; - if (typeof args[1] === 'function') { - return nativeMethod.apply(this, arguments) - .then(function() { - if (typeof args[1] === 'function') { - args[1].apply(null); - } - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - - return RTCPeerConnection; -}; - -},{"sdp":17}],17:[function(require,module,exports){ -/* eslint-env node */ -'use strict'; - -// SDP helpers. -var SDPUtils = {}; - -// Generate an alphanumeric identifier for cname or mids. -// TODO: use UUIDs instead? https://gist.github.com/jed/982883 -SDPUtils.generateIdentifier = function() { - return Math.random().toString(36).substr(2, 10); -}; - -// The RTCP CNAME used by all peerconnections from the same JS. -SDPUtils.localCName = SDPUtils.generateIdentifier(); - -// Splits SDP into lines, dealing with both CRLF and LF. -SDPUtils.splitLines = function(blob) { - return blob.trim().split('\n').map(function(line) { - return line.trim(); - }); -}; -// Splits SDP into sessionpart and mediasections. Ensures CRLF. -SDPUtils.splitSections = function(blob) { - var parts = blob.split('\nm='); - return parts.map(function(part, index) { - return (index > 0 ? 'm=' + part : part).trim() + '\r\n'; - }); -}; - -// returns the session description. -SDPUtils.getDescription = function(blob) { - var sections = SDPUtils.splitSections(blob); - return sections && sections[0]; -}; - -// returns the individual media sections. -SDPUtils.getMediaSections = function(blob) { - var sections = SDPUtils.splitSections(blob); - sections.shift(); - return sections; -}; - -// Returns lines that start with a certain prefix. -SDPUtils.matchPrefix = function(blob, prefix) { - return SDPUtils.splitLines(blob).filter(function(line) { - return line.indexOf(prefix) === 0; - }); -}; - -// Parses an ICE candidate line. Sample input: -// candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8 -// rport 55996" -SDPUtils.parseCandidate = function(line) { - var parts; - // Parse both variants. - if (line.indexOf('a=candidate:') === 0) { - parts = line.substring(12).split(' '); - } else { - parts = line.substring(10).split(' '); - } - - var candidate = { - foundation: parts[0], - component: parseInt(parts[1], 10), - protocol: parts[2].toLowerCase(), - priority: parseInt(parts[3], 10), - ip: parts[4], - address: parts[4], // address is an alias for ip. - port: parseInt(parts[5], 10), - // skip parts[6] == 'typ' - type: parts[7] - }; - - for (var i = 8; i < parts.length; i += 2) { - switch (parts[i]) { - case 'raddr': - candidate.relatedAddress = parts[i + 1]; - break; - case 'rport': - candidate.relatedPort = parseInt(parts[i + 1], 10); - break; - case 'tcptype': - candidate.tcpType = parts[i + 1]; - break; - case 'ufrag': - candidate.ufrag = parts[i + 1]; // for backward compability. - candidate.usernameFragment = parts[i + 1]; - break; - default: // extension handling, in particular ufrag - candidate[parts[i]] = parts[i + 1]; - break; - } - } - return candidate; -}; - -// Translates a candidate object into SDP candidate attribute. -SDPUtils.writeCandidate = function(candidate) { - var sdp = []; - sdp.push(candidate.foundation); - sdp.push(candidate.component); - sdp.push(candidate.protocol.toUpperCase()); - sdp.push(candidate.priority); - sdp.push(candidate.address || candidate.ip); - sdp.push(candidate.port); - - var type = candidate.type; - sdp.push('typ'); - sdp.push(type); - if (type !== 'host' && candidate.relatedAddress && - candidate.relatedPort) { - sdp.push('raddr'); - sdp.push(candidate.relatedAddress); - sdp.push('rport'); - sdp.push(candidate.relatedPort); - } - if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') { - sdp.push('tcptype'); - sdp.push(candidate.tcpType); - } - if (candidate.usernameFragment || candidate.ufrag) { - sdp.push('ufrag'); - sdp.push(candidate.usernameFragment || candidate.ufrag); - } - return 'candidate:' + sdp.join(' '); -}; - -// Parses an ice-options line, returns an array of option tags. -// a=ice-options:foo bar -SDPUtils.parseIceOptions = function(line) { - return line.substr(14).split(' '); -}; - -// Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input: -// a=rtpmap:111 opus/48000/2 -SDPUtils.parseRtpMap = function(line) { - var parts = line.substr(9).split(' '); - var parsed = { - payloadType: parseInt(parts.shift(), 10) // was: id - }; - - parts = parts[0].split('/'); - - parsed.name = parts[0]; - parsed.clockRate = parseInt(parts[1], 10); // was: clockrate - parsed.channels = parts.length === 3 ? parseInt(parts[2], 10) : 1; - // legacy alias, got renamed back to channels in ORTC. - parsed.numChannels = parsed.channels; - return parsed; -}; - -// Generate an a=rtpmap line from RTCRtpCodecCapability or -// RTCRtpCodecParameters. -SDPUtils.writeRtpMap = function(codec) { - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - var channels = codec.channels || codec.numChannels || 1; - return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate + - (channels !== 1 ? '/' + channels : '') + '\r\n'; -}; - -// Parses an a=extmap line (headerextension from RFC 5285). Sample input: -// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset -// a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset -SDPUtils.parseExtmap = function(line) { - var parts = line.substr(9).split(' '); - return { - id: parseInt(parts[0], 10), - direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv', - uri: parts[1] - }; -}; - -// Generates a=extmap line from RTCRtpHeaderExtensionParameters or -// RTCRtpHeaderExtension. -SDPUtils.writeExtmap = function(headerExtension) { - return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) + - (headerExtension.direction && headerExtension.direction !== 'sendrecv' - ? '/' + headerExtension.direction - : '') + - ' ' + headerExtension.uri + '\r\n'; -}; - -// Parses an ftmp line, returns dictionary. Sample input: -// a=fmtp:96 vbr=on;cng=on -// Also deals with vbr=on; cng=on -SDPUtils.parseFmtp = function(line) { - var parsed = {}; - var kv; - var parts = line.substr(line.indexOf(' ') + 1).split(';'); - for (var j = 0; j < parts.length; j++) { - kv = parts[j].trim().split('='); - parsed[kv[0].trim()] = kv[1]; - } - return parsed; -}; - -// Generates an a=ftmp line from RTCRtpCodecCapability or RTCRtpCodecParameters. -SDPUtils.writeFmtp = function(codec) { - var line = ''; - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - if (codec.parameters && Object.keys(codec.parameters).length) { - var params = []; - Object.keys(codec.parameters).forEach(function(param) { - if (codec.parameters[param]) { - params.push(param + '=' + codec.parameters[param]); - } else { - params.push(param); - } - }); - line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n'; - } - return line; -}; - -// Parses an rtcp-fb line, returns RTCPRtcpFeedback object. Sample input: -// a=rtcp-fb:98 nack rpsi -SDPUtils.parseRtcpFb = function(line) { - var parts = line.substr(line.indexOf(' ') + 1).split(' '); - return { - type: parts.shift(), - parameter: parts.join(' ') - }; -}; -// Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters. -SDPUtils.writeRtcpFb = function(codec) { - var lines = ''; - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - if (codec.rtcpFeedback && codec.rtcpFeedback.length) { - // FIXME: special handling for trr-int? - codec.rtcpFeedback.forEach(function(fb) { - lines += 'a=rtcp-fb:' + pt + ' ' + fb.type + - (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') + - '\r\n'; - }); - } - return lines; -}; - -// Parses an RFC 5576 ssrc media attribute. Sample input: -// a=ssrc:3735928559 cname:something -SDPUtils.parseSsrcMedia = function(line) { - var sp = line.indexOf(' '); - var parts = { - ssrc: parseInt(line.substr(7, sp - 7), 10) - }; - var colon = line.indexOf(':', sp); - if (colon > -1) { - parts.attribute = line.substr(sp + 1, colon - sp - 1); - parts.value = line.substr(colon + 1); - } else { - parts.attribute = line.substr(sp + 1); - } - return parts; -}; - -SDPUtils.parseSsrcGroup = function(line) { - var parts = line.substr(13).split(' '); - return { - semantics: parts.shift(), - ssrcs: parts.map(function(ssrc) { - return parseInt(ssrc, 10); - }) - }; -}; - -// Extracts the MID (RFC 5888) from a media section. -// returns the MID or undefined if no mid line was found. -SDPUtils.getMid = function(mediaSection) { - var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0]; - if (mid) { - return mid.substr(6); - } -}; - -SDPUtils.parseFingerprint = function(line) { - var parts = line.substr(14).split(' '); - return { - algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge. - value: parts[1] - }; -}; - -// Extracts DTLS parameters from SDP media section or sessionpart. -// FIXME: for consistency with other functions this should only -// get the fingerprint line as input. See also getIceParameters. -SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) { - var lines = SDPUtils.matchPrefix(mediaSection + sessionpart, - 'a=fingerprint:'); - // Note: a=setup line is ignored since we use the 'auto' role. - // Note2: 'algorithm' is not case sensitive except in Edge. - return { - role: 'auto', - fingerprints: lines.map(SDPUtils.parseFingerprint) - }; -}; - -// Serializes DTLS parameters to SDP. -SDPUtils.writeDtlsParameters = function(params, setupType) { - var sdp = 'a=setup:' + setupType + '\r\n'; - params.fingerprints.forEach(function(fp) { - sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n'; - }); - return sdp; -}; - -// Parses a=crypto lines into -// https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#dictionary-rtcsrtpsdesparameters-members -SDPUtils.parseCryptoLine = function(line) { - var parts = line.substr(9).split(' '); - return { - tag: parseInt(parts[0], 10), - cryptoSuite: parts[1], - keyParams: parts[2], - sessionParams: parts.slice(3), - }; -}; - -SDPUtils.writeCryptoLine = function(parameters) { - return 'a=crypto:' + parameters.tag + ' ' + - parameters.cryptoSuite + ' ' + - (typeof parameters.keyParams === 'object' - ? SDPUtils.writeCryptoKeyParams(parameters.keyParams) - : parameters.keyParams) + - (parameters.sessionParams ? ' ' + parameters.sessionParams.join(' ') : '') + - '\r\n'; -}; - -// Parses the crypto key parameters into -// https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#rtcsrtpkeyparam* -SDPUtils.parseCryptoKeyParams = function(keyParams) { - if (keyParams.indexOf('inline:') !== 0) { - return null; - } - var parts = keyParams.substr(7).split('|'); - return { - keyMethod: 'inline', - keySalt: parts[0], - lifeTime: parts[1], - mkiValue: parts[2] ? parts[2].split(':')[0] : undefined, - mkiLength: parts[2] ? parts[2].split(':')[1] : undefined, - }; -}; - -SDPUtils.writeCryptoKeyParams = function(keyParams) { - return keyParams.keyMethod + ':' - + keyParams.keySalt + - (keyParams.lifeTime ? '|' + keyParams.lifeTime : '') + - (keyParams.mkiValue && keyParams.mkiLength - ? '|' + keyParams.mkiValue + ':' + keyParams.mkiLength - : ''); -}; - -// Extracts all SDES paramters. -SDPUtils.getCryptoParameters = function(mediaSection, sessionpart) { - var lines = SDPUtils.matchPrefix(mediaSection + sessionpart, - 'a=crypto:'); - return lines.map(SDPUtils.parseCryptoLine); -}; - -// Parses ICE information from SDP media section or sessionpart. -// FIXME: for consistency with other functions this should only -// get the ice-ufrag and ice-pwd lines as input. -SDPUtils.getIceParameters = function(mediaSection, sessionpart) { - var ufrag = SDPUtils.matchPrefix(mediaSection + sessionpart, - 'a=ice-ufrag:')[0]; - var pwd = SDPUtils.matchPrefix(mediaSection + sessionpart, - 'a=ice-pwd:')[0]; - if (!(ufrag && pwd)) { - return null; - } - return { - usernameFragment: ufrag.substr(12), - password: pwd.substr(10), - }; -}; - -// Serializes ICE parameters to SDP. -SDPUtils.writeIceParameters = function(params) { - return 'a=ice-ufrag:' + params.usernameFragment + '\r\n' + - 'a=ice-pwd:' + params.password + '\r\n'; -}; - -// Parses the SDP media section and returns RTCRtpParameters. -SDPUtils.parseRtpParameters = function(mediaSection) { - var description = { - codecs: [], - headerExtensions: [], - fecMechanisms: [], - rtcp: [] - }; - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].split(' '); - for (var i = 3; i < mline.length; i++) { // find all codecs from mline[3..] - var pt = mline[i]; - var rtpmapline = SDPUtils.matchPrefix( - mediaSection, 'a=rtpmap:' + pt + ' ')[0]; - if (rtpmapline) { - var codec = SDPUtils.parseRtpMap(rtpmapline); - var fmtps = SDPUtils.matchPrefix( - mediaSection, 'a=fmtp:' + pt + ' '); - // Only the first a=fmtp: is considered. - codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {}; - codec.rtcpFeedback = SDPUtils.matchPrefix( - mediaSection, 'a=rtcp-fb:' + pt + ' ') - .map(SDPUtils.parseRtcpFb); - description.codecs.push(codec); - // parse FEC mechanisms from rtpmap lines. - switch (codec.name.toUpperCase()) { - case 'RED': - case 'ULPFEC': - description.fecMechanisms.push(codec.name.toUpperCase()); - break; - default: // only RED and ULPFEC are recognized as FEC mechanisms. - break; - } - } - } - SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(function(line) { - description.headerExtensions.push(SDPUtils.parseExtmap(line)); - }); - // FIXME: parse rtcp. - return description; -}; - -// Generates parts of the SDP media section describing the capabilities / -// parameters. -SDPUtils.writeRtpDescription = function(kind, caps) { - var sdp = ''; - - // Build the mline. - sdp += 'm=' + kind + ' '; - sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs. - sdp += ' UDP/TLS/RTP/SAVPF '; - sdp += caps.codecs.map(function(codec) { - if (codec.preferredPayloadType !== undefined) { - return codec.preferredPayloadType; - } - return codec.payloadType; - }).join(' ') + '\r\n'; - - sdp += 'c=IN IP4 0.0.0.0\r\n'; - sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n'; - - // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb. - caps.codecs.forEach(function(codec) { - sdp += SDPUtils.writeRtpMap(codec); - sdp += SDPUtils.writeFmtp(codec); - sdp += SDPUtils.writeRtcpFb(codec); - }); - var maxptime = 0; - caps.codecs.forEach(function(codec) { - if (codec.maxptime > maxptime) { - maxptime = codec.maxptime; - } - }); - if (maxptime > 0) { - sdp += 'a=maxptime:' + maxptime + '\r\n'; - } - sdp += 'a=rtcp-mux\r\n'; - - if (caps.headerExtensions) { - caps.headerExtensions.forEach(function(extension) { - sdp += SDPUtils.writeExtmap(extension); - }); - } - // FIXME: write fecMechanisms. - return sdp; -}; - -// Parses the SDP media section and returns an array of -// RTCRtpEncodingParameters. -SDPUtils.parseRtpEncodingParameters = function(mediaSection) { - var encodingParameters = []; - var description = SDPUtils.parseRtpParameters(mediaSection); - var hasRed = description.fecMechanisms.indexOf('RED') !== -1; - var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1; - - // filter a=ssrc:... cname:, ignore PlanB-msid - var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(parts) { - return parts.attribute === 'cname'; - }); - var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc; - var secondarySsrc; - - var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID') - .map(function(line) { - var parts = line.substr(17).split(' '); - return parts.map(function(part) { - return parseInt(part, 10); - }); - }); - if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) { - secondarySsrc = flows[0][1]; - } - - description.codecs.forEach(function(codec) { - if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) { - var encParam = { - ssrc: primarySsrc, - codecPayloadType: parseInt(codec.parameters.apt, 10) - }; - if (primarySsrc && secondarySsrc) { - encParam.rtx = {ssrc: secondarySsrc}; - } - encodingParameters.push(encParam); - if (hasRed) { - encParam = JSON.parse(JSON.stringify(encParam)); - encParam.fec = { - ssrc: primarySsrc, - mechanism: hasUlpfec ? 'red+ulpfec' : 'red' - }; - encodingParameters.push(encParam); - } - } - }); - if (encodingParameters.length === 0 && primarySsrc) { - encodingParameters.push({ - ssrc: primarySsrc - }); - } - - // we support both b=AS and b=TIAS but interpret AS as TIAS. - var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b='); - if (bandwidth.length) { - if (bandwidth[0].indexOf('b=TIAS:') === 0) { - bandwidth = parseInt(bandwidth[0].substr(7), 10); - } else if (bandwidth[0].indexOf('b=AS:') === 0) { - // use formula from JSEP to convert b=AS to TIAS value. - bandwidth = parseInt(bandwidth[0].substr(5), 10) * 1000 * 0.95 - - (50 * 40 * 8); - } else { - bandwidth = undefined; - } - encodingParameters.forEach(function(params) { - params.maxBitrate = bandwidth; - }); - } - return encodingParameters; -}; - -// parses http://draft.ortc.org/#rtcrtcpparameters* -SDPUtils.parseRtcpParameters = function(mediaSection) { - var rtcpParameters = {}; - - // Gets the first SSRC. Note tha with RTX there might be multiple - // SSRCs. - var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(obj) { - return obj.attribute === 'cname'; - })[0]; - if (remoteSsrc) { - rtcpParameters.cname = remoteSsrc.value; - rtcpParameters.ssrc = remoteSsrc.ssrc; - } - - // Edge uses the compound attribute instead of reducedSize - // compound is !reducedSize - var rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize'); - rtcpParameters.reducedSize = rsize.length > 0; - rtcpParameters.compound = rsize.length === 0; - - // parses the rtcp-mux attrіbute. - // Note that Edge does not support unmuxed RTCP. - var mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux'); - rtcpParameters.mux = mux.length > 0; - - return rtcpParameters; -}; - -// parses either a=msid: or a=ssrc:... msid lines and returns -// the id of the MediaStream and MediaStreamTrack. -SDPUtils.parseMsid = function(mediaSection) { - var parts; - var spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:'); - if (spec.length === 1) { - parts = spec[0].substr(7).split(' '); - return {stream: parts[0], track: parts[1]}; - } - var planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(msidParts) { - return msidParts.attribute === 'msid'; - }); - if (planB.length > 0) { - parts = planB[0].value.split(' '); - return {stream: parts[0], track: parts[1]}; - } -}; - -// SCTP -// parses draft-ietf-mmusic-sctp-sdp-26 first and falls back -// to draft-ietf-mmusic-sctp-sdp-05 -SDPUtils.parseSctpDescription = function(mediaSection) { - var mline = SDPUtils.parseMLine(mediaSection); - var maxSizeLine = SDPUtils.matchPrefix(mediaSection, 'a=max-message-size:'); - var maxMessageSize; - if (maxSizeLine.length > 0) { - maxMessageSize = parseInt(maxSizeLine[0].substr(19), 10); - } - if (isNaN(maxMessageSize)) { - maxMessageSize = 65536; - } - var sctpPort = SDPUtils.matchPrefix(mediaSection, 'a=sctp-port:'); - if (sctpPort.length > 0) { - return { - port: parseInt(sctpPort[0].substr(12), 10), - protocol: mline.fmt, - maxMessageSize: maxMessageSize - }; - } - var sctpMapLines = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:'); - if (sctpMapLines.length > 0) { - var parts = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:')[0] - .substr(10) - .split(' '); - return { - port: parseInt(parts[0], 10), - protocol: parts[1], - maxMessageSize: maxMessageSize - }; - } -}; - -// SCTP -// outputs the draft-ietf-mmusic-sctp-sdp-26 version that all browsers -// support by now receiving in this format, unless we originally parsed -// as the draft-ietf-mmusic-sctp-sdp-05 format (indicated by the m-line -// protocol of DTLS/SCTP -- without UDP/ or TCP/) -SDPUtils.writeSctpDescription = function(media, sctp) { - var output = []; - if (media.protocol !== 'DTLS/SCTP') { - output = [ - 'm=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.protocol + '\r\n', - 'c=IN IP4 0.0.0.0\r\n', - 'a=sctp-port:' + sctp.port + '\r\n' - ]; - } else { - output = [ - 'm=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.port + '\r\n', - 'c=IN IP4 0.0.0.0\r\n', - 'a=sctpmap:' + sctp.port + ' ' + sctp.protocol + ' 65535\r\n' - ]; - } - if (sctp.maxMessageSize !== undefined) { - output.push('a=max-message-size:' + sctp.maxMessageSize + '\r\n'); - } - return output.join(''); -}; - -// Generate a session ID for SDP. -// https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1 -// recommends using a cryptographically random +ve 64-bit value -// but right now this should be acceptable and within the right range -SDPUtils.generateSessionId = function() { - return Math.random().toString().substr(2, 21); -}; - -// Write boilder plate for start of SDP -// sessId argument is optional - if not supplied it will -// be generated randomly -// sessVersion is optional and defaults to 2 -// sessUser is optional and defaults to 'thisisadapterortc' -SDPUtils.writeSessionBoilerplate = function(sessId, sessVer, sessUser) { - var sessionId; - var version = sessVer !== undefined ? sessVer : 2; - if (sessId) { - sessionId = sessId; - } else { - sessionId = SDPUtils.generateSessionId(); - } - var user = sessUser || 'thisisadapterortc'; - // FIXME: sess-id should be an NTP timestamp. - return 'v=0\r\n' + - 'o=' + user + ' ' + sessionId + ' ' + version + - ' IN IP4 127.0.0.1\r\n' + - 's=-\r\n' + - 't=0 0\r\n'; -}; - -SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) { - var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps); - - // Map ICE parameters (ufrag, pwd) to SDP. - sdp += SDPUtils.writeIceParameters( - transceiver.iceGatherer.getLocalParameters()); - - // Map DTLS parameters to SDP. - sdp += SDPUtils.writeDtlsParameters( - transceiver.dtlsTransport.getLocalParameters(), - type === 'offer' ? 'actpass' : 'active'); - - sdp += 'a=mid:' + transceiver.mid + '\r\n'; - - if (transceiver.direction) { - sdp += 'a=' + transceiver.direction + '\r\n'; - } else if (transceiver.rtpSender && transceiver.rtpReceiver) { - sdp += 'a=sendrecv\r\n'; - } else if (transceiver.rtpSender) { - sdp += 'a=sendonly\r\n'; - } else if (transceiver.rtpReceiver) { - sdp += 'a=recvonly\r\n'; - } else { - sdp += 'a=inactive\r\n'; - } - - if (transceiver.rtpSender) { - // spec. - var msid = 'msid:' + stream.id + ' ' + - transceiver.rtpSender.track.id + '\r\n'; - sdp += 'a=' + msid; - - // for Chrome. - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + - ' ' + msid; - if (transceiver.sendEncodingParameters[0].rtx) { - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + - ' ' + msid; - sdp += 'a=ssrc-group:FID ' + - transceiver.sendEncodingParameters[0].ssrc + ' ' + - transceiver.sendEncodingParameters[0].rtx.ssrc + - '\r\n'; - } - } - // FIXME: this should be written by writeRtpDescription. - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + - ' cname:' + SDPUtils.localCName + '\r\n'; - if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) { - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + - ' cname:' + SDPUtils.localCName + '\r\n'; - } - return sdp; -}; - -// Gets the direction from the mediaSection or the sessionpart. -SDPUtils.getDirection = function(mediaSection, sessionpart) { - // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv. - var lines = SDPUtils.splitLines(mediaSection); - for (var i = 0; i < lines.length; i++) { - switch (lines[i]) { - case 'a=sendrecv': - case 'a=sendonly': - case 'a=recvonly': - case 'a=inactive': - return lines[i].substr(2); - default: - // FIXME: What should happen here? - } - } - if (sessionpart) { - return SDPUtils.getDirection(sessionpart); - } - return 'sendrecv'; -}; - -SDPUtils.getKind = function(mediaSection) { - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].split(' '); - return mline[0].substr(2); -}; - -SDPUtils.isRejected = function(mediaSection) { - return mediaSection.split(' ', 2)[1] === '0'; -}; - -SDPUtils.parseMLine = function(mediaSection) { - var lines = SDPUtils.splitLines(mediaSection); - var parts = lines[0].substr(2).split(' '); - return { - kind: parts[0], - port: parseInt(parts[1], 10), - protocol: parts[2], - fmt: parts.slice(3).join(' ') - }; -}; - -SDPUtils.parseOLine = function(mediaSection) { - var line = SDPUtils.matchPrefix(mediaSection, 'o=')[0]; - var parts = line.substr(2).split(' '); - return { - username: parts[0], - sessionId: parts[1], - sessionVersion: parseInt(parts[2], 10), - netType: parts[3], - addressType: parts[4], - address: parts[5] - }; -}; - -// a very naive interpretation of a valid SDP. -SDPUtils.isValidSDP = function(blob) { - if (typeof blob !== 'string' || blob.length === 0) { - return false; - } - var lines = SDPUtils.splitLines(blob); - for (var i = 0; i < lines.length; i++) { - if (lines[i].length < 2 || lines[i].charAt(1) !== '=') { - return false; - } - // TODO: check the modifier a bit more. - } - return true; -}; - -// Expose public methods. -if (typeof module === 'object') { - module.exports = SDPUtils; -} - -},{}]},{},[1])(1) -}); diff --git a/static/kevin-master/assets/js/getHTMLMediaElement.js b/static/kevin-master/assets/js/getHTMLMediaElement.js deleted file mode 100644 index 9186b89..0000000 --- a/static/kevin-master/assets/js/getHTMLMediaElement.js +++ /dev/null @@ -1,512 +0,0 @@ -// __________________ -// getHTMLMediaElement.js - -function getHTMLMediaElement(mediaElement, config) { - config = config || {}; - - if (!mediaElement.nodeName || (mediaElement.nodeName.toLowerCase() != 'audio' && mediaElement.nodeName.toLowerCase() != 'video')) { - if (!mediaElement.getVideoTracks().length) { - return getAudioElement(mediaElement, config); - } - - var mediaStream = mediaElement; - mediaElement = document.createElement(mediaStream.getVideoTracks().length ? 'video' : 'audio'); - - try { - mediaElement.setAttributeNode(document.createAttribute('autoplay')); - mediaElement.setAttributeNode(document.createAttribute('playsinline')); - } catch (e) { - mediaElement.setAttribute('autoplay', true); - mediaElement.setAttribute('playsinline', true); - } - - if ('srcObject' in mediaElement) { - mediaElement.srcObject = mediaStream; - } else { - mediaElement[!!navigator.mozGetUserMedia ? 'mozSrcObject' : 'src'] = !!navigator.mozGetUserMedia ? mediaStream : (window.URL || window.webkitURL).createObjectURL(mediaStream); - } - } - - if (mediaElement.nodeName && mediaElement.nodeName.toLowerCase() == 'audio') { - return getAudioElement(mediaElement, config); - } - - var buttons = config.buttons || ['mute-audio', 'mute-video', 'full-screen', 'volume-slider', 'stop']; - buttons.has = function(element) { - return buttons.indexOf(element) !== -1; - }; - - config.toggle = config.toggle || []; - config.toggle.has = function(element) { - return config.toggle.indexOf(element) !== -1; - }; - - var mediaElementContainer = document.createElement('div'); - mediaElementContainer.className = 'media-container'; - - var mediaControls = document.createElement('div'); - mediaControls.className = 'media-controls'; - mediaElementContainer.appendChild(mediaControls); - - if (buttons.has('mute-audio')) { - var muteAudio = document.createElement('div'); - muteAudio.className = 'control ' + (config.toggle.has('mute-audio') ? 'unmute-audio selected' : 'mute-audio'); - mediaControls.appendChild(muteAudio); - - muteAudio.onclick = function() { - if (muteAudio.className.indexOf('unmute-audio') != -1) { - muteAudio.className = muteAudio.className.replace('unmute-audio selected', 'mute-audio'); - mediaElement.muted = false; - mediaElement.volume = 1; - if (config.onUnMuted) config.onUnMuted('audio'); - } else { - muteAudio.className = muteAudio.className.replace('mute-audio', 'unmute-audio selected'); - mediaElement.muted = true; - mediaElement.volume = 0; - if (config.onMuted) config.onMuted('audio'); - } - }; - } - - if (buttons.has('mute-video')) { - var muteVideo = document.createElement('div'); - muteVideo.className = 'control ' + (config.toggle.has('mute-video') ? 'unmute-video selected' : 'mute-video'); - mediaControls.appendChild(muteVideo); - - muteVideo.onclick = function() { - if (muteVideo.className.indexOf('unmute-video') != -1) { - muteVideo.className = muteVideo.className.replace('unmute-video selected', 'mute-video'); - mediaElement.muted = false; - mediaElement.volume = 1; - mediaElement.play(); - if (config.onUnMuted) config.onUnMuted('video'); - } else { - muteVideo.className = muteVideo.className.replace('mute-video', 'unmute-video selected'); - mediaElement.muted = true; - mediaElement.volume = 0; - mediaElement.pause(); - if (config.onMuted) config.onMuted('video'); - } - }; - } - - if (buttons.has('take-snapshot')) { - var takeSnapshot = document.createElement('div'); - takeSnapshot.className = 'control take-snapshot'; - mediaControls.appendChild(takeSnapshot); - - takeSnapshot.onclick = function() { - if (config.onTakeSnapshot) config.onTakeSnapshot(); - }; - } - - if (buttons.has('stop')) { - var stop = document.createElement('div'); - stop.className = 'control stop'; - mediaControls.appendChild(stop); - - stop.onclick = function() { - mediaElementContainer.style.opacity = 0; - setTimeout(function() { - if (mediaElementContainer.parentNode) { - mediaElementContainer.parentNode.removeChild(mediaElementContainer); - } - }, 800); - if (config.onStopped) config.onStopped(); - }; - } - - var volumeControl = document.createElement('div'); - volumeControl.className = 'volume-control'; - - if (buttons.has('record-audio')) { - var recordAudio = document.createElement('div'); - recordAudio.className = 'control ' + (config.toggle.has('record-audio') ? 'stop-recording-audio selected' : 'record-audio'); - volumeControl.appendChild(recordAudio); - - recordAudio.onclick = function() { - if (recordAudio.className.indexOf('stop-recording-audio') != -1) { - recordAudio.className = recordAudio.className.replace('stop-recording-audio selected', 'record-audio'); - if (config.onRecordingStopped) config.onRecordingStopped('audio'); - } else { - recordAudio.className = recordAudio.className.replace('record-audio', 'stop-recording-audio selected'); - if (config.onRecordingStarted) config.onRecordingStarted('audio'); - } - }; - } - - if (buttons.has('record-video')) { - var recordVideo = document.createElement('div'); - recordVideo.className = 'control ' + (config.toggle.has('record-video') ? 'stop-recording-video selected' : 'record-video'); - volumeControl.appendChild(recordVideo); - - recordVideo.onclick = function() { - if (recordVideo.className.indexOf('stop-recording-video') != -1) { - recordVideo.className = recordVideo.className.replace('stop-recording-video selected', 'record-video'); - if (config.onRecordingStopped) config.onRecordingStopped('video'); - } else { - recordVideo.className = recordVideo.className.replace('record-video', 'stop-recording-video selected'); - if (config.onRecordingStarted) config.onRecordingStarted('video'); - } - }; - } - - if (buttons.has('volume-slider')) { - var volumeSlider = document.createElement('div'); - volumeSlider.className = 'control volume-slider'; - volumeControl.appendChild(volumeSlider); - - var slider = document.createElement('input'); - slider.type = 'range'; - slider.min = 0; - slider.max = 100; - slider.value = 100; - slider.onchange = function() { - mediaElement.volume = '.' + slider.value.toString().substr(0, 1); - }; - volumeSlider.appendChild(slider); - } - - if (buttons.has('full-screen')) { - var zoom = document.createElement('div'); - zoom.className = 'control ' + (config.toggle.has('zoom-in') ? 'zoom-out selected' : 'zoom-in'); - - if (!slider && !recordAudio && !recordVideo && zoom) { - mediaControls.insertBefore(zoom, mediaControls.firstChild); - } else volumeControl.appendChild(zoom); - - zoom.onclick = function() { - if (zoom.className.indexOf('zoom-out') != -1) { - zoom.className = zoom.className.replace('zoom-out selected', 'zoom-in'); - exitFullScreen(); - } else { - zoom.className = zoom.className.replace('zoom-in', 'zoom-out selected'); - launchFullscreen(mediaElementContainer); - } - }; - - function launchFullscreen(element) { - if (element.requestFullscreen) { - element.requestFullscreen(); - } else if (element.mozRequestFullScreen) { - element.mozRequestFullScreen(); - } else if (element.webkitRequestFullscreen) { - element.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); - } - } - - function exitFullScreen() { - if (document.fullscreen) { - document.exitFullscreen(); - } - - if (document.mozFullScreen) { - document.mozCancelFullScreen(); - } - - if (document.webkitIsFullScreen) { - document.webkitExitFullscreen(); - } - } - - function screenStateChange(e) { - if (e.srcElement != mediaElementContainer) return; - - var isFullScreeMode = document.webkitIsFullScreen || document.mozFullScreen || document.fullscreen; - - mediaElementContainer.style.width = (isFullScreeMode ? (window.innerWidth - 20) : config.width) + 'px'; - mediaElementContainer.style.display = isFullScreeMode ? 'block' : 'inline-block'; - - if (config.height) { - mediaBox.style.height = (isFullScreeMode ? (window.innerHeight - 20) : config.height) + 'px'; - } - - if (!isFullScreeMode && config.onZoomout) config.onZoomout(); - if (isFullScreeMode && config.onZoomin) config.onZoomin(); - - if (!isFullScreeMode && zoom.className.indexOf('zoom-out') != -1) { - zoom.className = zoom.className.replace('zoom-out selected', 'zoom-in'); - if (config.onZoomout) config.onZoomout(); - } - setTimeout(adjustControls, 1000); - } - - document.addEventListener('fullscreenchange', screenStateChange, false); - document.addEventListener('mozfullscreenchange', screenStateChange, false); - document.addEventListener('webkitfullscreenchange', screenStateChange, false); - } - - if (buttons.has('volume-slider') || buttons.has('full-screen') || buttons.has('record-audio') || buttons.has('record-video')) { - mediaElementContainer.appendChild(volumeControl); - } - - var mediaBox = document.createElement('div'); - mediaBox.className = 'media-box'; - mediaElementContainer.appendChild(mediaBox); - - if (config.title) { - var h2 = document.createElement('h2'); - h2.innerHTML = config.title; - h2.setAttribute('style', 'position: absolute;color:white;font-size:17px;text-shadow: 1px 1px black;padding:0;margin:0;text-align: left; margin-top: 10px; margin-left: 10px; display: block; border: 0;line-height:1.5;z-index:1;'); - mediaBox.appendChild(h2); - } - - mediaBox.appendChild(mediaElement); - - if (!config.width) config.width = (innerWidth / 2) - 50; - - mediaElementContainer.style.width = config.width + 'px'; - - if (config.height) { - mediaBox.style.height = config.height + 'px'; - } - - mediaBox.querySelector('video').style.maxHeight = innerHeight + 'px'; - - var times = 0; - - function adjustControls() { - mediaControls.style.marginLeft = (mediaElementContainer.clientWidth - mediaControls.clientWidth - 2) + 'px'; - - if (slider) { - slider.style.width = (mediaElementContainer.clientWidth / 3) + 'px'; - volumeControl.style.marginLeft = (mediaElementContainer.clientWidth / 3 - 30) + 'px'; - - if (zoom) zoom.style['border-top-right-radius'] = '5px'; - } else { - volumeControl.style.marginLeft = (mediaElementContainer.clientWidth - volumeControl.clientWidth - 2) + 'px'; - } - - volumeControl.style.marginTop = (mediaElementContainer.clientHeight - volumeControl.clientHeight - 2) + 'px'; - - if (times < 10) { - times++; - setTimeout(adjustControls, 1000); - } else times = 0; - } - - if (config.showOnMouseEnter || typeof config.showOnMouseEnter === 'undefined') { - mediaElementContainer.onmouseenter = mediaElementContainer.onmousedown = function() { - adjustControls(); - mediaControls.style.opacity = 1; - volumeControl.style.opacity = 1; - }; - - mediaElementContainer.onmouseleave = function() { - mediaControls.style.opacity = 0; - volumeControl.style.opacity = 0; - }; - } else { - setTimeout(function() { - adjustControls(); - setTimeout(function() { - mediaControls.style.opacity = 1; - volumeControl.style.opacity = 1; - }, 300); - }, 700); - } - - adjustControls(); - - mediaElementContainer.toggle = function(clasName) { - if (typeof clasName != 'string') { - for (var i = 0; i < clasName.length; i++) { - mediaElementContainer.toggle(clasName[i]); - } - return; - } - - if (clasName == 'mute-audio' && muteAudio) muteAudio.onclick(); - if (clasName == 'mute-video' && muteVideo) muteVideo.onclick(); - - if (clasName == 'record-audio' && recordAudio) recordAudio.onclick(); - if (clasName == 'record-video' && recordVideo) recordVideo.onclick(); - - if (clasName == 'stop' && stop) stop.onclick(); - - return this; - }; - - mediaElementContainer.media = mediaElement; - - return mediaElementContainer; -} - -// __________________ -// getAudioElement.js - -function getAudioElement(mediaElement, config) { - config = config || {}; - - if (!mediaElement.nodeName || (mediaElement.nodeName.toLowerCase() != 'audio' && mediaElement.nodeName.toLowerCase() != 'video')) { - var mediaStream = mediaElement; - mediaElement = document.createElement('audio'); - - try { - mediaElement.setAttributeNode(document.createAttribute('autoplay')); - mediaElement.setAttributeNode(document.createAttribute('controls')); - } catch (e) { - mediaElement.setAttribute('autoplay', true); - mediaElement.setAttribute('controls', true); - } - - if ('srcObject' in mediaElement) { - mediaElement.mediaElement = mediaStream; - } else { - mediaElement[!!navigator.mozGetUserMedia ? 'mozSrcObject' : 'src'] = !!navigator.mozGetUserMedia ? mediaStream : (window.URL || window.webkitURL).createObjectURL(mediaStream); - } - } - - config.toggle = config.toggle || []; - config.toggle.has = function(element) { - return config.toggle.indexOf(element) !== -1; - }; - - var mediaElementContainer = document.createElement('div'); - mediaElementContainer.className = 'media-container'; - - var mediaControls = document.createElement('div'); - mediaControls.className = 'media-controls'; - mediaElementContainer.appendChild(mediaControls); - - var muteAudio = document.createElement('div'); - muteAudio.className = 'control ' + (config.toggle.has('mute-audio') ? 'unmute-audio selected' : 'mute-audio'); - mediaControls.appendChild(muteAudio); - - muteAudio.style['border-top-left-radius'] = '5px'; - - muteAudio.onclick = function() { - if (muteAudio.className.indexOf('unmute-audio') != -1) { - muteAudio.className = muteAudio.className.replace('unmute-audio selected', 'mute-audio'); - mediaElement.muted = false; - if (config.onUnMuted) config.onUnMuted('audio'); - } else { - muteAudio.className = muteAudio.className.replace('mute-audio', 'unmute-audio selected'); - mediaElement.muted = true; - if (config.onMuted) config.onMuted('audio'); - } - }; - - if (!config.buttons || (config.buttons && config.buttons.indexOf('record-audio') != -1)) { - var recordAudio = document.createElement('div'); - recordAudio.className = 'control ' + (config.toggle.has('record-audio') ? 'stop-recording-audio selected' : 'record-audio'); - mediaControls.appendChild(recordAudio); - - recordAudio.onclick = function() { - if (recordAudio.className.indexOf('stop-recording-audio') != -1) { - recordAudio.className = recordAudio.className.replace('stop-recording-audio selected', 'record-audio'); - if (config.onRecordingStopped) config.onRecordingStopped('audio'); - } else { - recordAudio.className = recordAudio.className.replace('record-audio', 'stop-recording-audio selected'); - if (config.onRecordingStarted) config.onRecordingStarted('audio'); - } - }; - } - - var volumeSlider = document.createElement('div'); - volumeSlider.className = 'control volume-slider'; - volumeSlider.style.width = 'auto'; - mediaControls.appendChild(volumeSlider); - - var slider = document.createElement('input'); - slider.style.marginTop = '11px'; - slider.style.width = ' 200px'; - - if (config.buttons && config.buttons.indexOf('record-audio') == -1) { - slider.style.width = ' 241px'; - } - - slider.type = 'range'; - slider.min = 0; - slider.max = 100; - slider.value = 100; - slider.onchange = function() { - mediaElement.volume = '.' + slider.value.toString().substr(0, 1); - }; - volumeSlider.appendChild(slider); - - var stop = document.createElement('div'); - stop.className = 'control stop'; - mediaControls.appendChild(stop); - - stop.onclick = function() { - mediaElementContainer.style.opacity = 0; - setTimeout(function() { - if (mediaElementContainer.parentNode) { - mediaElementContainer.parentNode.removeChild(mediaElementContainer); - } - }, 800); - if (config.onStopped) config.onStopped(); - }; - - stop.style['border-top-right-radius'] = '5px'; - stop.style['border-bottom-right-radius'] = '5px'; - - var mediaBox = document.createElement('div'); - mediaBox.className = 'media-box'; - mediaElementContainer.appendChild(mediaBox); - - var h2 = document.createElement('h2'); - h2.innerHTML = config.title || 'Audio Element'; - h2.setAttribute('style', 'position: absolute;color: rgb(160, 160, 160);font-size: 20px;text-shadow: 1px 1px rgb(255, 255, 255);padding:0;margin:0;'); - mediaBox.appendChild(h2); - - mediaBox.appendChild(mediaElement); - - mediaElementContainer.style.width = '329px'; - mediaBox.style.height = '90px'; - - h2.style.width = mediaElementContainer.style.width; - h2.style.height = '50px'; - h2.style.overflow = 'hidden'; - - var times = 0; - - function adjustControls() { - mediaControls.style.marginLeft = (mediaElementContainer.clientWidth - mediaControls.clientWidth - 7) + 'px'; - mediaControls.style.marginTop = (mediaElementContainer.clientHeight - mediaControls.clientHeight - 6) + 'px'; - if (times < 10) { - times++; - setTimeout(adjustControls, 1000); - } else times = 0; - } - - if (config.showOnMouseEnter || typeof config.showOnMouseEnter === 'undefined') { - mediaElementContainer.onmouseenter = mediaElementContainer.onmousedown = function() { - adjustControls(); - mediaControls.style.opacity = 1; - }; - - mediaElementContainer.onmouseleave = function() { - mediaControls.style.opacity = 0; - }; - } else { - setTimeout(function() { - adjustControls(); - setTimeout(function() { - mediaControls.style.opacity = 1; - }, 300); - }, 700); - } - - adjustControls(); - - mediaElementContainer.toggle = function(clasName) { - if (typeof clasName != 'string') { - for (var i = 0; i < clasName.length; i++) { - mediaElementContainer.toggle(clasName[i]); - } - return; - } - - if (clasName == 'mute-audio' && muteAudio) muteAudio.onclick(); - if (clasName == 'record-audio' && recordAudio) recordAudio.onclick(); - if (clasName == 'stop' && stop) stop.onclick(); - - return this; - }; - - mediaElementContainer.media = mediaElement; - - return mediaElementContainer; -} diff --git a/static/kevin-master/assets/js/jquery.min.js b/static/kevin-master/assets/js/jquery.min.js deleted file mode 100644 index d467083..0000000 --- a/static/kevin-master/assets/js/jquery.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v3.5.1 | (c) JS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,j=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function qe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function Le(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function He(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=$e(y.pixelPosition,function(e,t){if(t)return t=Be(e,n),Me.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 - - - - - - Home - KEVIN - - - - - - - - - - -
-
- -
-
-
-
-
-
-
-
- - -
-
-
-
- -
-
-
-
- -
-
- -
-
- -
-
-
-
- -
-
- -
-
- - - - - - - - - - - - - diff --git a/static/kevin-master/video-conferencing.html b/static/kevin-master/video-conferencing.html deleted file mode 100644 index 80ad6ff..0000000 --- a/static/kevin-master/video-conferencing.html +++ /dev/null @@ -1,470 +0,0 @@ - - - - - Video Conferencing using RTCMultiConnection - - - - - -

- Video Conferencing using RTCMultiConnection -

- Multi-user (many-to-many) video chat using mesh networking model. -

-

- -
-
- - - -

- - - - - - -
- -
- - -
- - - - - - - - - - - - - - diff --git a/static/kevin-master/view.html b/static/kevin-master/view.html deleted file mode 100644 index f2e7df0..0000000 --- a/static/kevin-master/view.html +++ /dev/null @@ -1,326 +0,0 @@ - - - - - - - OBS view - KEVIN - - - - - - - - - -
- - - - - - - - - - - - - -