mirror of
https://github.com/YunoHost-Apps/linuxdash_ynh.git
synced 2024-09-03 19:36:07 +02:00
Add update sources from 3 February 2016.
This commit is contained in:
parent
324aa8930b
commit
d88d2c6362
80 changed files with 4988 additions and 0 deletions
12
sources/.editorconfig
Executable file
12
sources/.editorconfig
Executable file
|
@ -0,0 +1,12 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
2
sources/.gitignore
vendored
Normal file
2
sources/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
vendor
|
||||||
|
node_modules
|
20
sources/LICENSE.md
Normal file
20
sources/LICENSE.md
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 afaqurk
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
54
sources/README.md
Normal file
54
sources/README.md
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<br/>
|
||||||
|
<h1 align="center"><i>Linux Dash</i></h1>
|
||||||
|
|
||||||
|
<h6 align="center">
|
||||||
|
<i>A simple, low-overhead web dashboard for Linux</i>
|
||||||
|
</h6>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<strong>
|
||||||
|
<a href="http://linuxdash.afaqtariq.com"><i>Demo</i></a> |
|
||||||
|
<a href="#features"><i>Features</i></a> |
|
||||||
|
<a href="https://github.com/afaqurk/linux-dash/wiki/Install-Linux-Dash">
|
||||||
|
<i>Installation</i></a> |
|
||||||
|
<a href="#support"><i>Support</i></a>
|
||||||
|
</strong>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://gitter.im/afaqurk/linux-dash">
|
||||||
|
<img
|
||||||
|
src="https://badges.gitter.im/gitterHQ/gitter.png"
|
||||||
|
alt="Linux Dash Gitter chat">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<p align="center">
|
||||||
|
<a href="http://linuxdash.afaqtariq.com">
|
||||||
|
<img
|
||||||
|
width="80%"
|
||||||
|
alt="Linux Dash screenshot"
|
||||||
|
src="http://i.imgur.com/tehGyrQ.gif">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
## Features
|
||||||
|
* A beautiful, simple web-based dashboard for monitoring a linux server
|
||||||
|
* Only ~1MB on disk! *(.git removed)*
|
||||||
|
* Live graphs, refresh-able widgets, and a growing # of supported modules
|
||||||
|
* Drop-in installation for PHP, Node.js, Python, and Go
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For help with general setup and configuration issues please use the [Linux Dash Gitter chat room](https://gitter.im/afaqurk/linux-dash).
|
||||||
|
|
||||||
|
The following distributions are supported:
|
||||||
|
* Arch
|
||||||
|
* Debian 6,7
|
||||||
|
* Ubuntu 11.04+
|
||||||
|
* Linux Mint 16+
|
||||||
|
* CentOS 5, 6
|
||||||
|
* openSUSE
|
22
sources/composer.json
Normal file
22
sources/composer.json
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"name": "afaqurk/linux-dash",
|
||||||
|
"description": "A drop-in, low-overhead monitoring web dashboard for a linux machine.",
|
||||||
|
"license": "MIT",
|
||||||
|
"version": "1.2.0",
|
||||||
|
"keywords": ["linux", "dashboard", "linux-dash", "server dashboard"],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Afaq Tariq",
|
||||||
|
"email": "afaq05@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.4.0"
|
||||||
|
},
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/afaqurk/linux-dash/issues?state=open",
|
||||||
|
"forum": "https://gitter.im/afaqurk/linux-dash",
|
||||||
|
"source": "https://github.com/afaqurk/linux-dash"
|
||||||
|
}
|
||||||
|
}
|
6
sources/css/animate.css
vendored
Normal file
6
sources/css/animate.css
vendored
Normal file
File diff suppressed because one or more lines are too long
488
sources/css/main.css
Normal file
488
sources/css/main.css
Normal file
|
@ -0,0 +1,488 @@
|
||||||
|
/***** Template ****/
|
||||||
|
* {
|
||||||
|
font-family: 'Merriweather', Arial, sans-serif;
|
||||||
|
letter-spacing: .1rem;
|
||||||
|
}
|
||||||
|
html {
|
||||||
|
margin-top: 0px;
|
||||||
|
padding-top: 0;
|
||||||
|
border-top: 1px solid #4F8EF7;
|
||||||
|
|
||||||
|
background: url(../img/themes/crossword.png);
|
||||||
|
|
||||||
|
-webkit-transition: all 1s ease;
|
||||||
|
-moz-transition: all 1s ease;
|
||||||
|
-ms-transition: all 1s ease;
|
||||||
|
-o-transition: all 1s ease;
|
||||||
|
transition: all 1s ease;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
color: rgb(34, 34, 34);
|
||||||
|
display: block;
|
||||||
|
font-size: 30px;
|
||||||
|
font-weight: 300;
|
||||||
|
height: 32px;
|
||||||
|
letter-spacing: .1rem;
|
||||||
|
line-height: 52.5px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
margin-top: 0px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.plugin ::-webkit-scrollbar {
|
||||||
|
width: 5px;
|
||||||
|
}
|
||||||
|
.plugin ::-webkit-scrollbar-button {
|
||||||
|
width: 8px;
|
||||||
|
height:5px;
|
||||||
|
}
|
||||||
|
.plugin ::-webkit-scrollbar-track {
|
||||||
|
background:#eee;
|
||||||
|
border: thin solid lightgray;
|
||||||
|
box-shadow: 0px 0px 3px #dfdfdf inset;
|
||||||
|
border-radius:10px;
|
||||||
|
}
|
||||||
|
.plugin ::-webkit-scrollbar-thumb {
|
||||||
|
background: #999;
|
||||||
|
border: thin solid gray;
|
||||||
|
border-radius:10px;
|
||||||
|
}
|
||||||
|
.plugin ::-webkit-scrollbar-thumb:hover {
|
||||||
|
background:#7d7d7d;
|
||||||
|
}
|
||||||
|
.centered {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.hero {
|
||||||
|
padding: 10px 0 20px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.hero nav-bar {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.hero nav-bar ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style-type: none;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
.hero nav-bar ul li a {
|
||||||
|
font-size: 11px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: .2rem;
|
||||||
|
margin-right: 35px;
|
||||||
|
text-decoration: none;
|
||||||
|
line-height: 2.3rem;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
.hero nav-bar ul li.active a,
|
||||||
|
.hero nav-bar ul li a:hover {
|
||||||
|
color: #1EAEDB;
|
||||||
|
}
|
||||||
|
.hero nav-bar ul li {
|
||||||
|
margin-left: 20px;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
.hero nav-bar ul li a {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
#theme-switcher {
|
||||||
|
position: fixed;
|
||||||
|
top: 25px;
|
||||||
|
right: -371px;
|
||||||
|
border-radius: 5px 0px 0px 5px;
|
||||||
|
padding: 4px;
|
||||||
|
z-index: 999999;
|
||||||
|
cursor: pointer;
|
||||||
|
color: rgb(255, 255, 255);
|
||||||
|
background-color: #517fa4;
|
||||||
|
|
||||||
|
-webkit-transition: all 0.5s ease;
|
||||||
|
-moz-transition: all 0.5s ease;
|
||||||
|
-ms-transition: all 0.5s ease;
|
||||||
|
-o-transition: all 0.5s ease;
|
||||||
|
transition: all 0.5s ease;
|
||||||
|
}
|
||||||
|
#theme-switcher .settings-icon{
|
||||||
|
font-size: 25px;
|
||||||
|
height: 100%;
|
||||||
|
margin-top: 5px;
|
||||||
|
float: left;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
#theme-switcher .settings-icon:hover{
|
||||||
|
color: #243949;
|
||||||
|
}
|
||||||
|
#theme-switcher.open {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
#theme-switcher .option {
|
||||||
|
margin: 5px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 5px;
|
||||||
|
color: black;
|
||||||
|
background-color: #ececec;
|
||||||
|
border-radius: 2px;
|
||||||
|
-webkit-transition: all 0.5s ease;
|
||||||
|
-moz-transition: all 0.5s ease;
|
||||||
|
-ms-transition: all 0.5s ease;
|
||||||
|
-o-transition: all 0.5s ease;
|
||||||
|
transition: all 0.5s ease;
|
||||||
|
}
|
||||||
|
#theme-switcher .option:hover,
|
||||||
|
#theme-switcher .option.selected {
|
||||||
|
box-shadow: 0 5px 10px rgba(0,0,0,.53),0 3px 10px rgba(0,0,0,.16);
|
||||||
|
background-color: #FFF94C;
|
||||||
|
}
|
||||||
|
#theme-switcher .option.selected:hover {
|
||||||
|
background-color: lightgrey;
|
||||||
|
}
|
||||||
|
@media (min-width: 1080px) {
|
||||||
|
#plugins {
|
||||||
|
float: none;
|
||||||
|
margin: 0 auto;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 1079px) {
|
||||||
|
#plugins {
|
||||||
|
float: none;
|
||||||
|
margin: 0 auto;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Plugins Container ****/
|
||||||
|
#plugins {
|
||||||
|
padding: 20px;
|
||||||
|
padding-top: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
border: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Plugin ****/
|
||||||
|
.plugin {
|
||||||
|
float: left;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
color: black;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 2px;
|
||||||
|
box-shadow: 0 5px 10px rgba(0,0,0,.53),0 3px 10px rgba(0,0,0,.16);
|
||||||
|
margin-top: 10px;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-left: 50px;
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.plugin {
|
||||||
|
max-width: 80%;
|
||||||
|
float: none;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.plugin-body {
|
||||||
|
max-height: 400px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.plugin .top-bar {
|
||||||
|
height: 25px;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
letter-spacing: .1rem;
|
||||||
|
line-height: 1.3rem;
|
||||||
|
font-size: 11px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #009587;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.plugin .no-padding {
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
.plugin-body {
|
||||||
|
height: 400px;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 10px;
|
||||||
|
line-height: 30px;
|
||||||
|
overflow: auto;
|
||||||
|
border-top: 1px solid #ececec;
|
||||||
|
}
|
||||||
|
.plugin last-update{
|
||||||
|
font-size: 11px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
no-data {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
refresh-btn button {
|
||||||
|
background-color: #009587;
|
||||||
|
border: 0;
|
||||||
|
float: right;
|
||||||
|
font-size: 15px;
|
||||||
|
color: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
-webkit-transition: all 0.5s ease;
|
||||||
|
-moz-transition: all 0.5s ease;
|
||||||
|
-ms-transition: all 0.5s ease;
|
||||||
|
-o-transition: all 0.5s ease;
|
||||||
|
transition: all 0.5s ease;
|
||||||
|
|
||||||
|
box-shadow: 0 1px 6px rgba(0,0,0,.12),0 1px 6px rgba(0,0,0,.5);
|
||||||
|
}
|
||||||
|
refresh-btn button:hover {
|
||||||
|
background-color: #ffeb3b;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
refresh-btn button:active {
|
||||||
|
background-color: #0f9d58;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**** Loader ****/
|
||||||
|
.spinner {
|
||||||
|
margin: 100px auto;
|
||||||
|
width: 50px;
|
||||||
|
height: 30px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner > div {
|
||||||
|
background-color: #009587;
|
||||||
|
height: 100%;
|
||||||
|
width: 6px;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
-webkit-animation: stretchdelay 1.2s infinite ease-in-out;
|
||||||
|
animation: stretchdelay 1.2s infinite ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner .rect2 {
|
||||||
|
-webkit-animation-delay: -1.1s;
|
||||||
|
animation-delay: -1.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner .rect3 {
|
||||||
|
-webkit-animation-delay: -1.0s;
|
||||||
|
animation-delay: -1.0s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner .rect4 {
|
||||||
|
-webkit-animation-delay: -0.9s;
|
||||||
|
animation-delay: -0.9s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner .rect5 {
|
||||||
|
-webkit-animation-delay: -0.8s;
|
||||||
|
animation-delay: -0.8s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes stretchdelay {
|
||||||
|
0%, 40%, 100% { -webkit-transform: scaleY(0.4) }
|
||||||
|
20% { -webkit-transform: scaleY(1.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes stretchdelay {
|
||||||
|
0%, 40%, 100% {
|
||||||
|
transform: scaleY(0.4);
|
||||||
|
-webkit-transform: scaleY(0.4);
|
||||||
|
} 20% {
|
||||||
|
transform: scaleY(1.0);
|
||||||
|
-webkit-transform: scaleY(1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**** General Elements ****/
|
||||||
|
table
|
||||||
|
{
|
||||||
|
font-size: 10px;
|
||||||
|
margin: 0;
|
||||||
|
min-width: 400px;
|
||||||
|
border-collapse: collapse;
|
||||||
|
text-align: left;
|
||||||
|
table-layout:fixed;
|
||||||
|
}
|
||||||
|
table th,
|
||||||
|
table td {
|
||||||
|
padding: 5px;
|
||||||
|
max-width: 250px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
table th
|
||||||
|
{
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
border-bottom: 1px solid #f1f1f1;
|
||||||
|
}
|
||||||
|
table td {
|
||||||
|
border-bottom: 1px solid #f1f1f1;
|
||||||
|
padding: 9px 8px;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
font-size: 11px;
|
||||||
|
letter-spacing: .1em;
|
||||||
|
color: rgba(0,0,0,.65);
|
||||||
|
}
|
||||||
|
table tbody tr:hover td
|
||||||
|
{
|
||||||
|
background-color: #fafafa;
|
||||||
|
}
|
||||||
|
table.metrics-table {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
canvas {
|
||||||
|
float: none;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
/*********************************************
|
||||||
|
Widget Elements
|
||||||
|
*********************************************/
|
||||||
|
.progress-bar {
|
||||||
|
background-color: #eec;
|
||||||
|
border-radius: 10px; /* (height of inner div) / 2 + padding */
|
||||||
|
padding: 0px;
|
||||||
|
clear: both;
|
||||||
|
display: inline-block;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.progress-bar > div {
|
||||||
|
background-color: #1EAEDB;
|
||||||
|
width: 0%;
|
||||||
|
height: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
.table-data-plugin .filter-container {
|
||||||
|
padding-bottom: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.table-data-plugin .filter,
|
||||||
|
.table-data-plugin .filter:focus,
|
||||||
|
.table-data-plugin .filter:active {
|
||||||
|
height: 20px;
|
||||||
|
padding: 5px;
|
||||||
|
margin: 5px;
|
||||||
|
border: none;
|
||||||
|
outline-color: transparent;
|
||||||
|
background: transparent;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
.table-data-plugin .filter:focus {
|
||||||
|
border-bottom: 1px solid #ff5722;
|
||||||
|
}
|
||||||
|
.table-data-plugin thead tr th a,
|
||||||
|
.table-data-plugin thead tr th a:visited {
|
||||||
|
color: black;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.table-data-plugin .column-sort-caret {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #1EAEDB;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Popover
|
||||||
|
* http://codepen.io/derekpcollins/pen/JCLhG/
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* The element to hover over */
|
||||||
|
.qs {
|
||||||
|
cursor: default;
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.qs .popover {
|
||||||
|
text-transform: none;
|
||||||
|
background-color: rgba(0, 0, 0, 0.85);
|
||||||
|
border-radius: 5px;
|
||||||
|
bottom: 42px;
|
||||||
|
box-shadow: 0 0 5px rgba(0, 0, 0, 0.4);
|
||||||
|
color: #fff;
|
||||||
|
display: none;
|
||||||
|
font-size: 12px;
|
||||||
|
font-family: 'Helvetica',sans-serif;
|
||||||
|
padding: 7px 10px;
|
||||||
|
position: absolute;
|
||||||
|
left: -80px;
|
||||||
|
width: 200px;
|
||||||
|
z-index: 4;
|
||||||
|
}
|
||||||
|
.qs .popover:before {
|
||||||
|
border-top: 7px solid rgba(0, 0, 0, 0.85);
|
||||||
|
border-right: 7px solid transparent;
|
||||||
|
border-left: 7px solid transparent;
|
||||||
|
bottom: -7px;
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -7px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
.qs:hover .popover {
|
||||||
|
display: block;
|
||||||
|
-webkit-animation: fade-in .3s linear 1, move-up .3s linear 1;
|
||||||
|
-moz-animation: fade-in .3s linear 1, move-up .3s linear 1;
|
||||||
|
-ms-animation: fade-in .3s linear 1, move-up .3s linear 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes fade-in {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-moz-keyframes fade-in {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-ms-keyframes fade-in {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes move-up {
|
||||||
|
from {
|
||||||
|
bottom: 30px;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
bottom: 42px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-moz-keyframes move-up {
|
||||||
|
from {
|
||||||
|
bottom: 30px;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
bottom: 42px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-ms-keyframes move-up {
|
||||||
|
from {
|
||||||
|
bottom: 30px;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
bottom: 42px;
|
||||||
|
}
|
||||||
|
}
|
170
sources/css/theme-old.css
Normal file
170
sources/css/theme-old.css
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
/**************************************
|
||||||
|
Theme: linux-dash beta
|
||||||
|
**************************************/
|
||||||
|
html.old {
|
||||||
|
background: #F9F6F1;
|
||||||
|
}
|
||||||
|
html.old body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
html.old body * {
|
||||||
|
font-family: "Open Sans";
|
||||||
|
letter-spacing: 0;
|
||||||
|
}
|
||||||
|
html.old body .hero {
|
||||||
|
background: #00BA8B;
|
||||||
|
color: #ffffff;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
html.old body .hero h4 {
|
||||||
|
color: #ffffff;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
height: 40px;
|
||||||
|
line-height: 35px;
|
||||||
|
margin: 0;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
html.old body .hero small {
|
||||||
|
letter-spacing: 0.1rem;
|
||||||
|
line-height: 40px;
|
||||||
|
margin-left: 20px;
|
||||||
|
opacity: 0.9;
|
||||||
|
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
html.old body .hero #theme-switcher {
|
||||||
|
right: -315px;
|
||||||
|
}
|
||||||
|
html.old body .hero #theme-switcher.open {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
html.old body .hero nav-bar {
|
||||||
|
background: #ffffff;
|
||||||
|
border-bottom: 1px solid #d6d6d6;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
html.old body .hero nav-bar br {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
html.old body .hero nav-bar ul {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
html.old body .hero nav-bar ul li {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
html.old body .hero nav-bar ul li:not(:first-child) {
|
||||||
|
border-left: 1px solid #e6e6e6;
|
||||||
|
}
|
||||||
|
html.old body .hero nav-bar ul li a {
|
||||||
|
color: #B2AFAA;
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 30px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 15px;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
html.old body .hero nav-bar ul li:hover a {
|
||||||
|
color: #888888;
|
||||||
|
}
|
||||||
|
html.old body #plugins {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
html.old body .plugin {
|
||||||
|
border: 1px solid #d5d5d5;
|
||||||
|
border-radius: 0 0 5px 5px;
|
||||||
|
box-shadow: none;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
html.old body .plugin .top-bar {
|
||||||
|
background: transparent linear-gradient(to bottom, #f9f6f1 0%, #f2efea 100%) repeat scroll 0px 0px;
|
||||||
|
border-bottom: 1px solid #d6d6d6;
|
||||||
|
color: #525252;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
padding: 0 0 0 15px;
|
||||||
|
position: relative;
|
||||||
|
text-align: left;
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
html.old body .plugin .top-bar last-update {
|
||||||
|
float: right;
|
||||||
|
margin: 0 10px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
html.old body .plugin .top-bar refresh-btn {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
html.old body .plugin .top-bar refresh-btn button {
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.15);
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.1) inset, 0px 1px 2px rgba(0, 0, 0, 0.1);
|
||||||
|
color: #555555;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: none;
|
||||||
|
display: inline-block;
|
||||||
|
float: none;
|
||||||
|
font-size: 14px;
|
||||||
|
height: auto;
|
||||||
|
margin: 0 -5px 0 10px;
|
||||||
|
padding: 0 4px;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
html.old body .plugin .top-bar refresh-btn button:hover {
|
||||||
|
background: #e6e6e6;
|
||||||
|
}
|
||||||
|
html.old body .plugin .plugin-body {
|
||||||
|
border: none;
|
||||||
|
height: auto;
|
||||||
|
line-height: normal;
|
||||||
|
max-height: 300px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
html.old body .plugin .plugin-body table {
|
||||||
|
border-collapse: separate;
|
||||||
|
border-spacing: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
min-width: 300px;
|
||||||
|
}
|
||||||
|
html.old body .plugin .plugin-body table tr:not(:first-child) th {
|
||||||
|
border-top: 1px solid #dddddd;
|
||||||
|
}
|
||||||
|
html.old body .plugin .plugin-body table td,
|
||||||
|
html.old body .plugin .plugin-body table th {
|
||||||
|
border-bottom: none;
|
||||||
|
padding: 4px 5px;
|
||||||
|
}
|
||||||
|
html.old body .plugin .plugin-body table td:not(:first-child),
|
||||||
|
html.old body .plugin .plugin-body table th:not(:first-child) {
|
||||||
|
border-left: 1px solid #dddddd;
|
||||||
|
}
|
||||||
|
html.old body .plugin .plugin-body table th:not(.filter-container) {
|
||||||
|
background: transparent -moz-linear-gradient(center top, #fafafa 0%, #e9e9e9 100%) repeat scroll 0% 0%;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
html.old body .plugin .plugin-body table th.filter-container .filter {
|
||||||
|
border-bottom: none;
|
||||||
|
font-size: 12px;
|
||||||
|
height: auto;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
html.old body .plugin .plugin-body table th.filter-container .filter::before {
|
||||||
|
content: 'Search >';
|
||||||
|
opacity: 0.5;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
html.old body .plugin .plugin-body table td {
|
||||||
|
border-top: 1px solid #dddddd;
|
||||||
|
}
|
||||||
|
html.old body .plugin canvas {
|
||||||
|
width: 100%;
|
||||||
|
}
|
88
sources/css/themes.css
Normal file
88
sources/css/themes.css
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
@import "theme-old.css";
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
Theme: Winter
|
||||||
|
**************************************/
|
||||||
|
|
||||||
|
html.winter {
|
||||||
|
background: url(../img/themes/contemporary_china_2.png) ;
|
||||||
|
}
|
||||||
|
html.winter .hero nav-bar ul li.active a,
|
||||||
|
html.winter .hero nav-bar ul li a:hover {
|
||||||
|
color: #23568f;
|
||||||
|
}
|
||||||
|
html.winter .plugin {
|
||||||
|
background-color: rgba(255, 255, 255, 0.60);
|
||||||
|
}
|
||||||
|
html.winter .plugin .top-bar {
|
||||||
|
color: #012e40;
|
||||||
|
}
|
||||||
|
html.winter .plugin refresh-btn button {
|
||||||
|
background-color: #4c6c73;
|
||||||
|
}
|
||||||
|
table th {
|
||||||
|
color: #012e40;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
Theme: Summer
|
||||||
|
**************************************/
|
||||||
|
|
||||||
|
html.summer {
|
||||||
|
clear: both;
|
||||||
|
background: url(../img/themes/congruent_pentagon.png);
|
||||||
|
}
|
||||||
|
html.summer .hero nav-bar ul li.active a,
|
||||||
|
html.summer .hero nav-bar ul li a:hover {
|
||||||
|
color: #D84315;
|
||||||
|
}
|
||||||
|
html.summer .plugin{
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
}
|
||||||
|
html.summer .plugin .top-bar {
|
||||||
|
color: #BF360C;
|
||||||
|
}
|
||||||
|
html.summer .plugin refresh-btn button {
|
||||||
|
background-color: #BF360C;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
Theme: Spring
|
||||||
|
**************************************/
|
||||||
|
|
||||||
|
html.spring {
|
||||||
|
clear: both;
|
||||||
|
background: url(../img/themes/food.png);
|
||||||
|
}
|
||||||
|
html.spring .hero nav-bar ul li.active a,
|
||||||
|
html.spring .hero nav-bar ul li a:hover {
|
||||||
|
color: #E65100;
|
||||||
|
}
|
||||||
|
html.spring .plugin {
|
||||||
|
background-color: rgba(255,255,255,0.95);
|
||||||
|
}
|
||||||
|
html.spring .plugin .top-bar {
|
||||||
|
color: #FF6D00;
|
||||||
|
}
|
||||||
|
html.spring .plugin refresh-btn button {
|
||||||
|
background-color: #E65100;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
Theme: Fall
|
||||||
|
**************************************/
|
||||||
|
|
||||||
|
html.fall {
|
||||||
|
background: url(../img/themes/skulls.png);
|
||||||
|
}
|
||||||
|
html.fall .plugin {
|
||||||
|
background: url(../img/themes/crossword.png);
|
||||||
|
}
|
||||||
|
html.fall .hero nav-bar ul li.active a,
|
||||||
|
html.fall .hero nav-bar ul li a:hover,
|
||||||
|
html.fall .plugin .top-bar {
|
||||||
|
color: #F09819;
|
||||||
|
}
|
||||||
|
html.fall .plugin refresh-btn button {
|
||||||
|
background-color: #FF512F;
|
||||||
|
}
|
70
sources/demo.html
Normal file
70
sources/demo.html
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" ng-app="linuxDash">
|
||||||
|
<head>
|
||||||
|
<title>linux-dash : Server Monitoring Web Dashboard</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="description" content="Monitor your Linux server through a simple web dashboard. Open source and free!">
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
|
||||||
|
<link rel="icon" href="favicon.ico" type="image/x-icon">
|
||||||
|
<link href='http://fonts.googleapis.com/css?family=Merriweather:300italic,300|Open+Sans:400,600' rel='stylesheet' type='text/css'>
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/main.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/themes.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/animate.css">
|
||||||
|
|
||||||
|
<!-- Angular Libs -->
|
||||||
|
<script src="js/angular.min.js" type="text/javascript"></script>
|
||||||
|
<script src="js/angular-route.js" type="text/javascript"></script>
|
||||||
|
<!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="https://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
</head>
|
||||||
|
<body ng-controller="body">
|
||||||
|
|
||||||
|
<a href="https://github.com/afaqurk/linux-dash">
|
||||||
|
<img
|
||||||
|
style="position: absolute; top: 0; left: 0; border: 0; z-index:10;"
|
||||||
|
src="https://camo.githubusercontent.com/567c3a48d796e2fc06ea80409cc9dd82bf714434/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f6c6566745f6461726b626c75655f3132313632312e706e67"
|
||||||
|
alt="Fork me on GitHub"
|
||||||
|
data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_left_darkblue_121621.png">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="hero">
|
||||||
|
<h4 class="title">Linux Dash</h4>
|
||||||
|
|
||||||
|
<small>A simple linux dashboard</small>
|
||||||
|
|
||||||
|
<theme-switcher></theme-switcher>
|
||||||
|
|
||||||
|
<nav-bar></nav-bar>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div ng-if="!serverSet">
|
||||||
|
<h2>Setting server...</h2>
|
||||||
|
<loader></loader>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Templates Get Rendered Here -->
|
||||||
|
<div ng-if="serverSet" id="plugins" class="animated fadeInDown" ng-view></div>
|
||||||
|
|
||||||
|
<!-- Javascript-->
|
||||||
|
<!-- Placed at the end of the document so the pages load faster -->
|
||||||
|
<script src="js/linuxDash.js" type="text/javascript"></script>
|
||||||
|
<script src="js/modules.js" type="text/javascript"></script>
|
||||||
|
<script src="js/smoothie.min.js" type="text/javascript"></script>
|
||||||
|
<script async src="//www.google-analytics.com/analytics.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||||
|
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||||
|
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||||
|
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||||
|
|
||||||
|
ga('create', 'UA-44168418-2', 'auto');
|
||||||
|
ga('send', 'pageview');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
sources/favicon.ico
Normal file
BIN
sources/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 97 KiB |
BIN
sources/img/themes/congruent_pentagon.png
Normal file
BIN
sources/img/themes/congruent_pentagon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
BIN
sources/img/themes/contemporary_china_2.png
Normal file
BIN
sources/img/themes/contemporary_china_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
BIN
sources/img/themes/crossword.png
Normal file
BIN
sources/img/themes/crossword.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
BIN
sources/img/themes/food.png
Normal file
BIN
sources/img/themes/food.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.1 KiB |
BIN
sources/img/themes/skulls.png
Normal file
BIN
sources/img/themes/skulls.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 65 KiB |
45
sources/index.html
Normal file
45
sources/index.html
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" ng-app="linuxDash">
|
||||||
|
<head>
|
||||||
|
<title>linux-dash : Server Monitoring Web Dashboard</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="description" content="Monitor your Linux server through a simple web dashboard. Open source and free!">
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
|
||||||
|
<link rel="icon" href="favicon.ico" type="image/x-icon">
|
||||||
|
<link href='//fonts.googleapis.com/css?family=Merriweather:300italic,300|Open+Sans:400,600' rel='stylesheet' type='text/css'>
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/main.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/themes.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/animate.css">
|
||||||
|
|
||||||
|
<!-- Angular Libs -->
|
||||||
|
<script src="js/angular.min.js" type="text/javascript"></script>
|
||||||
|
<script src="js/angular-route.js" type="text/javascript"></script>
|
||||||
|
<!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="https://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="hero">
|
||||||
|
<h4 class="title">Linux Dash</h4>
|
||||||
|
<small>A simple linux dashboard</small>
|
||||||
|
<theme-switcher></theme-switcher>
|
||||||
|
<nav-bar></nav-bar>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Templates Get Rendered Here -->
|
||||||
|
<div
|
||||||
|
id="plugins"
|
||||||
|
class="animated fadeInDown"
|
||||||
|
ng-view>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Javascript-->
|
||||||
|
<!-- Placed at the end of the document so the pages load faster -->
|
||||||
|
<script src="js/linuxDash.js" type="text/javascript"></script>
|
||||||
|
<script src="js/modules.js" type="text/javascript"></script>
|
||||||
|
<script src="js/smoothie.min.js" type="text/javascript"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
996
sources/js/angular-route.js
vendored
Normal file
996
sources/js/angular-route.js
vendored
Normal file
|
@ -0,0 +1,996 @@
|
||||||
|
/**
|
||||||
|
* @license AngularJS v1.3.4
|
||||||
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
||||||
|
* License: MIT
|
||||||
|
*/
|
||||||
|
(function(window, angular, undefined) {'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc module
|
||||||
|
* @name ngRoute
|
||||||
|
* @description
|
||||||
|
*
|
||||||
|
* # ngRoute
|
||||||
|
*
|
||||||
|
* The `ngRoute` module provides routing and deeplinking services and directives for angular apps.
|
||||||
|
*
|
||||||
|
* ## Example
|
||||||
|
* See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* <div doc-module-components="ngRoute"></div>
|
||||||
|
*/
|
||||||
|
/* global -ngRouteModule */
|
||||||
|
var ngRouteModule = angular.module('ngRoute', ['ng']).
|
||||||
|
provider('$route', $RouteProvider),
|
||||||
|
$routeMinErr = angular.$$minErr('ngRoute');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc provider
|
||||||
|
* @name $routeProvider
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
*
|
||||||
|
* Used for configuring routes.
|
||||||
|
*
|
||||||
|
* ## Example
|
||||||
|
* See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
|
||||||
|
*
|
||||||
|
* ## Dependencies
|
||||||
|
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||||
|
*/
|
||||||
|
function $RouteProvider() {
|
||||||
|
function inherit(parent, extra) {
|
||||||
|
return angular.extend(Object.create(parent), extra);
|
||||||
|
}
|
||||||
|
|
||||||
|
var routes = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc method
|
||||||
|
* @name $routeProvider#when
|
||||||
|
*
|
||||||
|
* @param {string} path Route path (matched against `$location.path`). If `$location.path`
|
||||||
|
* contains redundant trailing slash or is missing one, the route will still match and the
|
||||||
|
* `$location.path` will be updated to add or drop the trailing slash to exactly match the
|
||||||
|
* route definition.
|
||||||
|
*
|
||||||
|
* * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up
|
||||||
|
* to the next slash are matched and stored in `$routeParams` under the given `name`
|
||||||
|
* when the route matches.
|
||||||
|
* * `path` can contain named groups starting with a colon and ending with a star:
|
||||||
|
* e.g.`:name*`. All characters are eagerly stored in `$routeParams` under the given `name`
|
||||||
|
* when the route matches.
|
||||||
|
* * `path` can contain optional named groups with a question mark: e.g.`:name?`.
|
||||||
|
*
|
||||||
|
* For example, routes like `/color/:color/largecode/:largecode*\/edit` will match
|
||||||
|
* `/color/brown/largecode/code/with/slashes/edit` and extract:
|
||||||
|
*
|
||||||
|
* * `color: brown`
|
||||||
|
* * `largecode: code/with/slashes`.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {Object} route Mapping information to be assigned to `$route.current` on route
|
||||||
|
* match.
|
||||||
|
*
|
||||||
|
* Object properties:
|
||||||
|
*
|
||||||
|
* - `controller` – `{(string|function()=}` – Controller fn that should be associated with
|
||||||
|
* newly created scope or the name of a {@link angular.Module#controller registered
|
||||||
|
* controller} if passed as a string.
|
||||||
|
* - `controllerAs` – `{string=}` – A controller alias name. If present the controller will be
|
||||||
|
* published to scope under the `controllerAs` name.
|
||||||
|
* - `template` – `{string=|function()=}` – html template as a string or a function that
|
||||||
|
* returns an html template as a string which should be used by {@link
|
||||||
|
* ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives.
|
||||||
|
* This property takes precedence over `templateUrl`.
|
||||||
|
*
|
||||||
|
* If `template` is a function, it will be called with the following parameters:
|
||||||
|
*
|
||||||
|
* - `{Array.<Object>}` - route parameters extracted from the current
|
||||||
|
* `$location.path()` by applying the current route
|
||||||
|
*
|
||||||
|
* - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
|
||||||
|
* template that should be used by {@link ngRoute.directive:ngView ngView}.
|
||||||
|
*
|
||||||
|
* If `templateUrl` is a function, it will be called with the following parameters:
|
||||||
|
*
|
||||||
|
* - `{Array.<Object>}` - route parameters extracted from the current
|
||||||
|
* `$location.path()` by applying the current route
|
||||||
|
*
|
||||||
|
* - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
|
||||||
|
* be injected into the controller. If any of these dependencies are promises, the router
|
||||||
|
* will wait for them all to be resolved or one to be rejected before the controller is
|
||||||
|
* instantiated.
|
||||||
|
* If all the promises are resolved successfully, the values of the resolved promises are
|
||||||
|
* injected and {@link ngRoute.$route#$routeChangeSuccess $routeChangeSuccess} event is
|
||||||
|
* fired. If any of the promises are rejected the
|
||||||
|
* {@link ngRoute.$route#$routeChangeError $routeChangeError} event is fired. The map object
|
||||||
|
* is:
|
||||||
|
*
|
||||||
|
* - `key` – `{string}`: a name of a dependency to be injected into the controller.
|
||||||
|
* - `factory` - `{string|function}`: If `string` then it is an alias for a service.
|
||||||
|
* Otherwise if function, then it is {@link auto.$injector#invoke injected}
|
||||||
|
* and the return value is treated as the dependency. If the result is a promise, it is
|
||||||
|
* resolved before its value is injected into the controller. Be aware that
|
||||||
|
* `ngRoute.$routeParams` will still refer to the previous route within these resolve
|
||||||
|
* functions. Use `$route.current.params` to access the new route parameters, instead.
|
||||||
|
*
|
||||||
|
* - `redirectTo` – {(string|function())=} – value to update
|
||||||
|
* {@link ng.$location $location} path with and trigger route redirection.
|
||||||
|
*
|
||||||
|
* If `redirectTo` is a function, it will be called with the following parameters:
|
||||||
|
*
|
||||||
|
* - `{Object.<string>}` - route parameters extracted from the current
|
||||||
|
* `$location.path()` by applying the current route templateUrl.
|
||||||
|
* - `{string}` - current `$location.path()`
|
||||||
|
* - `{Object}` - current `$location.search()`
|
||||||
|
*
|
||||||
|
* The custom `redirectTo` function is expected to return a string which will be used
|
||||||
|
* to update `$location.path()` and `$location.search()`.
|
||||||
|
*
|
||||||
|
* - `[reloadOnSearch=true]` - {boolean=} - reload route when only `$location.search()`
|
||||||
|
* or `$location.hash()` changes.
|
||||||
|
*
|
||||||
|
* If the option is set to `false` and url in the browser changes, then
|
||||||
|
* `$routeUpdate` event is broadcasted on the root scope.
|
||||||
|
*
|
||||||
|
* - `[caseInsensitiveMatch=false]` - {boolean=} - match routes without being case sensitive
|
||||||
|
*
|
||||||
|
* If the option is set to `true`, then the particular route can be matched without being
|
||||||
|
* case sensitive
|
||||||
|
*
|
||||||
|
* @returns {Object} self
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Adds a new route definition to the `$route` service.
|
||||||
|
*/
|
||||||
|
this.when = function(path, route) {
|
||||||
|
//copy original route object to preserve params inherited from proto chain
|
||||||
|
var routeCopy = angular.copy(route);
|
||||||
|
if (angular.isUndefined(routeCopy.reloadOnSearch)) {
|
||||||
|
routeCopy.reloadOnSearch = true;
|
||||||
|
}
|
||||||
|
if (angular.isUndefined(routeCopy.caseInsensitiveMatch)) {
|
||||||
|
routeCopy.caseInsensitiveMatch = this.caseInsensitiveMatch;
|
||||||
|
}
|
||||||
|
routes[path] = angular.extend(
|
||||||
|
routeCopy,
|
||||||
|
path && pathRegExp(path, routeCopy)
|
||||||
|
);
|
||||||
|
|
||||||
|
// create redirection for trailing slashes
|
||||||
|
if (path) {
|
||||||
|
var redirectPath = (path[path.length - 1] == '/')
|
||||||
|
? path.substr(0, path.length - 1)
|
||||||
|
: path + '/';
|
||||||
|
|
||||||
|
routes[redirectPath] = angular.extend(
|
||||||
|
{redirectTo: path},
|
||||||
|
pathRegExp(redirectPath, routeCopy)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc property
|
||||||
|
* @name $routeProvider#caseInsensitiveMatch
|
||||||
|
* @description
|
||||||
|
*
|
||||||
|
* A boolean property indicating if routes defined
|
||||||
|
* using this provider should be matched using a case sensitive
|
||||||
|
* algorithm. Defaults to `false`.
|
||||||
|
*/
|
||||||
|
this.caseInsensitiveMatch = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param path {string} path
|
||||||
|
* @param opts {Object} options
|
||||||
|
* @return {?Object}
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Normalizes the given path, returning a regular expression
|
||||||
|
* and the original path.
|
||||||
|
*
|
||||||
|
* Inspired by pathRexp in visionmedia/express/lib/utils.js.
|
||||||
|
*/
|
||||||
|
function pathRegExp(path, opts) {
|
||||||
|
var insensitive = opts.caseInsensitiveMatch,
|
||||||
|
ret = {
|
||||||
|
originalPath: path,
|
||||||
|
regexp: path
|
||||||
|
},
|
||||||
|
keys = ret.keys = [];
|
||||||
|
|
||||||
|
path = path
|
||||||
|
.replace(/([().])/g, '\\$1')
|
||||||
|
.replace(/(\/)?:(\w+)([\?\*])?/g, function(_, slash, key, option) {
|
||||||
|
var optional = option === '?' ? option : null;
|
||||||
|
var star = option === '*' ? option : null;
|
||||||
|
keys.push({ name: key, optional: !!optional });
|
||||||
|
slash = slash || '';
|
||||||
|
return ''
|
||||||
|
+ (optional ? '' : slash)
|
||||||
|
+ '(?:'
|
||||||
|
+ (optional ? slash : '')
|
||||||
|
+ (star && '(.+?)' || '([^/]+)')
|
||||||
|
+ (optional || '')
|
||||||
|
+ ')'
|
||||||
|
+ (optional || '');
|
||||||
|
})
|
||||||
|
.replace(/([\/$\*])/g, '\\$1');
|
||||||
|
|
||||||
|
ret.regexp = new RegExp('^' + path + '$', insensitive ? 'i' : '');
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc method
|
||||||
|
* @name $routeProvider#otherwise
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Sets route definition that will be used on route change when no other route definition
|
||||||
|
* is matched.
|
||||||
|
*
|
||||||
|
* @param {Object|string} params Mapping information to be assigned to `$route.current`.
|
||||||
|
* If called with a string, the value maps to `redirectTo`.
|
||||||
|
* @returns {Object} self
|
||||||
|
*/
|
||||||
|
this.otherwise = function(params) {
|
||||||
|
if (typeof params === 'string') {
|
||||||
|
params = {redirectTo: params};
|
||||||
|
}
|
||||||
|
this.when(null, params);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
this.$get = ['$rootScope',
|
||||||
|
'$location',
|
||||||
|
'$routeParams',
|
||||||
|
'$q',
|
||||||
|
'$injector',
|
||||||
|
'$templateRequest',
|
||||||
|
'$sce',
|
||||||
|
function($rootScope, $location, $routeParams, $q, $injector, $templateRequest, $sce) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc service
|
||||||
|
* @name $route
|
||||||
|
* @requires $location
|
||||||
|
* @requires $routeParams
|
||||||
|
*
|
||||||
|
* @property {Object} current Reference to the current route definition.
|
||||||
|
* The route definition contains:
|
||||||
|
*
|
||||||
|
* - `controller`: The controller constructor as define in route definition.
|
||||||
|
* - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for
|
||||||
|
* controller instantiation. The `locals` contain
|
||||||
|
* the resolved values of the `resolve` map. Additionally the `locals` also contain:
|
||||||
|
*
|
||||||
|
* - `$scope` - The current route scope.
|
||||||
|
* - `$template` - The current route template HTML.
|
||||||
|
*
|
||||||
|
* @property {Object} routes Object with all route configuration Objects as its properties.
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* `$route` is used for deep-linking URLs to controllers and views (HTML partials).
|
||||||
|
* It watches `$location.url()` and tries to map the path to an existing route definition.
|
||||||
|
*
|
||||||
|
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||||
|
*
|
||||||
|
* You can define routes through {@link ngRoute.$routeProvider $routeProvider}'s API.
|
||||||
|
*
|
||||||
|
* The `$route` service is typically used in conjunction with the
|
||||||
|
* {@link ngRoute.directive:ngView `ngView`} directive and the
|
||||||
|
* {@link ngRoute.$routeParams `$routeParams`} service.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* This example shows how changing the URL hash causes the `$route` to match a route against the
|
||||||
|
* URL, and the `ngView` pulls in the partial.
|
||||||
|
*
|
||||||
|
* <example name="$route-service" module="ngRouteExample"
|
||||||
|
* deps="angular-route.js" fixBase="true">
|
||||||
|
* <file name="index.html">
|
||||||
|
* <div ng-controller="MainController">
|
||||||
|
* Choose:
|
||||||
|
* <a href="Book/Moby">Moby</a> |
|
||||||
|
* <a href="Book/Moby/ch/1">Moby: Ch1</a> |
|
||||||
|
* <a href="Book/Gatsby">Gatsby</a> |
|
||||||
|
* <a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
|
||||||
|
* <a href="Book/Scarlet">Scarlet Letter</a><br/>
|
||||||
|
*
|
||||||
|
* <div ng-view></div>
|
||||||
|
*
|
||||||
|
* <hr />
|
||||||
|
*
|
||||||
|
* <pre>$location.path() = {{$location.path()}}</pre>
|
||||||
|
* <pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
|
||||||
|
* <pre>$route.current.params = {{$route.current.params}}</pre>
|
||||||
|
* <pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
|
||||||
|
* <pre>$routeParams = {{$routeParams}}</pre>
|
||||||
|
* </div>
|
||||||
|
* </file>
|
||||||
|
*
|
||||||
|
* <file name="book.html">
|
||||||
|
* controller: {{name}}<br />
|
||||||
|
* Book Id: {{params.bookId}}<br />
|
||||||
|
* </file>
|
||||||
|
*
|
||||||
|
* <file name="chapter.html">
|
||||||
|
* controller: {{name}}<br />
|
||||||
|
* Book Id: {{params.bookId}}<br />
|
||||||
|
* Chapter Id: {{params.chapterId}}
|
||||||
|
* </file>
|
||||||
|
*
|
||||||
|
* <file name="script.js">
|
||||||
|
* angular.module('ngRouteExample', ['ngRoute'])
|
||||||
|
*
|
||||||
|
* .controller('MainController', function($scope, $route, $routeParams, $location) {
|
||||||
|
* $scope.$route = $route;
|
||||||
|
* $scope.$location = $location;
|
||||||
|
* $scope.$routeParams = $routeParams;
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* .controller('BookController', function($scope, $routeParams) {
|
||||||
|
* $scope.name = "BookController";
|
||||||
|
* $scope.params = $routeParams;
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* .controller('ChapterController', function($scope, $routeParams) {
|
||||||
|
* $scope.name = "ChapterController";
|
||||||
|
* $scope.params = $routeParams;
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* .config(function($routeProvider, $locationProvider) {
|
||||||
|
* $routeProvider
|
||||||
|
* .when('/Book/:bookId', {
|
||||||
|
* templateUrl: 'book.html',
|
||||||
|
* controller: 'BookController',
|
||||||
|
* resolve: {
|
||||||
|
* // I will cause a 1 second delay
|
||||||
|
* delay: function($q, $timeout) {
|
||||||
|
* var delay = $q.defer();
|
||||||
|
* $timeout(delay.resolve, 1000);
|
||||||
|
* return delay.promise;
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* })
|
||||||
|
* .when('/Book/:bookId/ch/:chapterId', {
|
||||||
|
* templateUrl: 'chapter.html',
|
||||||
|
* controller: 'ChapterController'
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* // configure html5 to get links working on jsfiddle
|
||||||
|
* $locationProvider.html5Mode(true);
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* </file>
|
||||||
|
*
|
||||||
|
* <file name="protractor.js" type="protractor">
|
||||||
|
* it('should load and compile correct template', function() {
|
||||||
|
* element(by.linkText('Moby: Ch1')).click();
|
||||||
|
* var content = element(by.css('[ng-view]')).getText();
|
||||||
|
* expect(content).toMatch(/controller\: ChapterController/);
|
||||||
|
* expect(content).toMatch(/Book Id\: Moby/);
|
||||||
|
* expect(content).toMatch(/Chapter Id\: 1/);
|
||||||
|
*
|
||||||
|
* element(by.partialLinkText('Scarlet')).click();
|
||||||
|
*
|
||||||
|
* content = element(by.css('[ng-view]')).getText();
|
||||||
|
* expect(content).toMatch(/controller\: BookController/);
|
||||||
|
* expect(content).toMatch(/Book Id\: Scarlet/);
|
||||||
|
* });
|
||||||
|
* </file>
|
||||||
|
* </example>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc event
|
||||||
|
* @name $route#$routeChangeStart
|
||||||
|
* @eventType broadcast on root scope
|
||||||
|
* @description
|
||||||
|
* Broadcasted before a route change. At this point the route services starts
|
||||||
|
* resolving all of the dependencies needed for the route change to occur.
|
||||||
|
* Typically this involves fetching the view template as well as any dependencies
|
||||||
|
* defined in `resolve` route property. Once all of the dependencies are resolved
|
||||||
|
* `$routeChangeSuccess` is fired.
|
||||||
|
*
|
||||||
|
* The route change (and the `$location` change that triggered it) can be prevented
|
||||||
|
* by calling `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on}
|
||||||
|
* for more details about event object.
|
||||||
|
*
|
||||||
|
* @param {Object} angularEvent Synthetic event object.
|
||||||
|
* @param {Route} next Future route information.
|
||||||
|
* @param {Route} current Current route information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc event
|
||||||
|
* @name $route#$routeChangeSuccess
|
||||||
|
* @eventType broadcast on root scope
|
||||||
|
* @description
|
||||||
|
* Broadcasted after a route dependencies are resolved.
|
||||||
|
* {@link ngRoute.directive:ngView ngView} listens for the directive
|
||||||
|
* to instantiate the controller and render the view.
|
||||||
|
*
|
||||||
|
* @param {Object} angularEvent Synthetic event object.
|
||||||
|
* @param {Route} current Current route information.
|
||||||
|
* @param {Route|Undefined} previous Previous route information, or undefined if current is
|
||||||
|
* first route entered.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc event
|
||||||
|
* @name $route#$routeChangeError
|
||||||
|
* @eventType broadcast on root scope
|
||||||
|
* @description
|
||||||
|
* Broadcasted if any of the resolve promises are rejected.
|
||||||
|
*
|
||||||
|
* @param {Object} angularEvent Synthetic event object
|
||||||
|
* @param {Route} current Current route information.
|
||||||
|
* @param {Route} previous Previous route information.
|
||||||
|
* @param {Route} rejection Rejection of the promise. Usually the error of the failed promise.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc event
|
||||||
|
* @name $route#$routeUpdate
|
||||||
|
* @eventType broadcast on root scope
|
||||||
|
* @description
|
||||||
|
*
|
||||||
|
* The `reloadOnSearch` property has been set to false, and we are reusing the same
|
||||||
|
* instance of the Controller.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var forceReload = false,
|
||||||
|
preparedRoute,
|
||||||
|
preparedRouteIsUpdateOnly,
|
||||||
|
$route = {
|
||||||
|
routes: routes,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc method
|
||||||
|
* @name $route#reload
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Causes `$route` service to reload the current route even if
|
||||||
|
* {@link ng.$location $location} hasn't changed.
|
||||||
|
*
|
||||||
|
* As a result of that, {@link ngRoute.directive:ngView ngView}
|
||||||
|
* creates new scope and reinstantiates the controller.
|
||||||
|
*/
|
||||||
|
reload: function() {
|
||||||
|
forceReload = true;
|
||||||
|
$rootScope.$evalAsync(function() {
|
||||||
|
// Don't support cancellation of a reload for now...
|
||||||
|
prepareRoute();
|
||||||
|
commitRoute();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc method
|
||||||
|
* @name $route#updateParams
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Causes `$route` service to update the current URL, replacing
|
||||||
|
* current route parameters with those specified in `newParams`.
|
||||||
|
* Provided property names that match the route's path segment
|
||||||
|
* definitions will be interpolated into the location's path, while
|
||||||
|
* remaining properties will be treated as query params.
|
||||||
|
*
|
||||||
|
* @param {Object} newParams mapping of URL parameter names to values
|
||||||
|
*/
|
||||||
|
updateParams: function(newParams) {
|
||||||
|
if (this.current && this.current.$$route) {
|
||||||
|
var searchParams = {}, self=this;
|
||||||
|
|
||||||
|
angular.forEach(Object.keys(newParams), function(key) {
|
||||||
|
if (!self.current.pathParams[key]) searchParams[key] = newParams[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
newParams = angular.extend({}, this.current.params, newParams);
|
||||||
|
$location.path(interpolate(this.current.$$route.originalPath, newParams));
|
||||||
|
$location.search(angular.extend({}, $location.search(), searchParams));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw $routeMinErr('norout', 'Tried updating route when with no current route');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$rootScope.$on('$locationChangeStart', prepareRoute);
|
||||||
|
$rootScope.$on('$locationChangeSuccess', commitRoute);
|
||||||
|
|
||||||
|
return $route;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param on {string} current url
|
||||||
|
* @param route {Object} route regexp to match the url against
|
||||||
|
* @return {?Object}
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Check if the route matches the current url.
|
||||||
|
*
|
||||||
|
* Inspired by match in
|
||||||
|
* visionmedia/express/lib/router/router.js.
|
||||||
|
*/
|
||||||
|
function switchRouteMatcher(on, route) {
|
||||||
|
var keys = route.keys,
|
||||||
|
params = {};
|
||||||
|
|
||||||
|
if (!route.regexp) return null;
|
||||||
|
|
||||||
|
var m = route.regexp.exec(on);
|
||||||
|
if (!m) return null;
|
||||||
|
|
||||||
|
for (var i = 1, len = m.length; i < len; ++i) {
|
||||||
|
var key = keys[i - 1];
|
||||||
|
|
||||||
|
var val = m[i];
|
||||||
|
|
||||||
|
if (key && val) {
|
||||||
|
params[key.name] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareRoute($locationEvent) {
|
||||||
|
var lastRoute = $route.current;
|
||||||
|
|
||||||
|
preparedRoute = parseRoute();
|
||||||
|
preparedRouteIsUpdateOnly = preparedRoute && lastRoute && preparedRoute.$$route === lastRoute.$$route
|
||||||
|
&& angular.equals(preparedRoute.pathParams, lastRoute.pathParams)
|
||||||
|
&& !preparedRoute.reloadOnSearch && !forceReload;
|
||||||
|
|
||||||
|
if (!preparedRouteIsUpdateOnly && (lastRoute || preparedRoute)) {
|
||||||
|
if ($rootScope.$broadcast('$routeChangeStart', preparedRoute, lastRoute).defaultPrevented) {
|
||||||
|
if ($locationEvent) {
|
||||||
|
$locationEvent.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function commitRoute() {
|
||||||
|
var lastRoute = $route.current;
|
||||||
|
var nextRoute = preparedRoute;
|
||||||
|
|
||||||
|
if (preparedRouteIsUpdateOnly) {
|
||||||
|
lastRoute.params = nextRoute.params;
|
||||||
|
angular.copy(lastRoute.params, $routeParams);
|
||||||
|
$rootScope.$broadcast('$routeUpdate', lastRoute);
|
||||||
|
} else if (nextRoute || lastRoute) {
|
||||||
|
forceReload = false;
|
||||||
|
$route.current = nextRoute;
|
||||||
|
if (nextRoute) {
|
||||||
|
if (nextRoute.redirectTo) {
|
||||||
|
if (angular.isString(nextRoute.redirectTo)) {
|
||||||
|
$location.path(interpolate(nextRoute.redirectTo, nextRoute.params)).search(nextRoute.params)
|
||||||
|
.replace();
|
||||||
|
} else {
|
||||||
|
$location.url(nextRoute.redirectTo(nextRoute.pathParams, $location.path(), $location.search()))
|
||||||
|
.replace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$q.when(nextRoute).
|
||||||
|
then(function() {
|
||||||
|
if (nextRoute) {
|
||||||
|
var locals = angular.extend({}, nextRoute.resolve),
|
||||||
|
template, templateUrl;
|
||||||
|
|
||||||
|
angular.forEach(locals, function(value, key) {
|
||||||
|
locals[key] = angular.isString(value) ?
|
||||||
|
$injector.get(value) : $injector.invoke(value, null, null, key);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (angular.isDefined(template = nextRoute.template)) {
|
||||||
|
if (angular.isFunction(template)) {
|
||||||
|
template = template(nextRoute.params);
|
||||||
|
}
|
||||||
|
} else if (angular.isDefined(templateUrl = nextRoute.templateUrl)) {
|
||||||
|
if (angular.isFunction(templateUrl)) {
|
||||||
|
templateUrl = templateUrl(nextRoute.params);
|
||||||
|
}
|
||||||
|
templateUrl = $sce.getTrustedResourceUrl(templateUrl);
|
||||||
|
if (angular.isDefined(templateUrl)) {
|
||||||
|
nextRoute.loadedTemplateUrl = templateUrl;
|
||||||
|
template = $templateRequest(templateUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (angular.isDefined(template)) {
|
||||||
|
locals['$template'] = template;
|
||||||
|
}
|
||||||
|
return $q.all(locals);
|
||||||
|
}
|
||||||
|
}).
|
||||||
|
// after route change
|
||||||
|
then(function(locals) {
|
||||||
|
if (nextRoute == $route.current) {
|
||||||
|
if (nextRoute) {
|
||||||
|
nextRoute.locals = locals;
|
||||||
|
angular.copy(nextRoute.params, $routeParams);
|
||||||
|
}
|
||||||
|
$rootScope.$broadcast('$routeChangeSuccess', nextRoute, lastRoute);
|
||||||
|
}
|
||||||
|
}, function(error) {
|
||||||
|
if (nextRoute == $route.current) {
|
||||||
|
$rootScope.$broadcast('$routeChangeError', nextRoute, lastRoute, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Object} the current active route, by matching it against the URL
|
||||||
|
*/
|
||||||
|
function parseRoute() {
|
||||||
|
// Match a route
|
||||||
|
var params, match;
|
||||||
|
angular.forEach(routes, function(route, path) {
|
||||||
|
if (!match && (params = switchRouteMatcher($location.path(), route))) {
|
||||||
|
match = inherit(route, {
|
||||||
|
params: angular.extend({}, $location.search(), params),
|
||||||
|
pathParams: params});
|
||||||
|
match.$$route = route;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// No route matched; fallback to "otherwise" route
|
||||||
|
return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} interpolation of the redirect path with the parameters
|
||||||
|
*/
|
||||||
|
function interpolate(string, params) {
|
||||||
|
var result = [];
|
||||||
|
angular.forEach((string || '').split(':'), function(segment, i) {
|
||||||
|
if (i === 0) {
|
||||||
|
result.push(segment);
|
||||||
|
} else {
|
||||||
|
var segmentMatch = segment.match(/(\w+)(?:[?*])?(.*)/);
|
||||||
|
var key = segmentMatch[1];
|
||||||
|
result.push(params[key]);
|
||||||
|
result.push(segmentMatch[2] || '');
|
||||||
|
delete params[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result.join('');
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
ngRouteModule.provider('$routeParams', $RouteParamsProvider);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc service
|
||||||
|
* @name $routeParams
|
||||||
|
* @requires $route
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* The `$routeParams` service allows you to retrieve the current set of route parameters.
|
||||||
|
*
|
||||||
|
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||||
|
*
|
||||||
|
* The route parameters are a combination of {@link ng.$location `$location`}'s
|
||||||
|
* {@link ng.$location#search `search()`} and {@link ng.$location#path `path()`}.
|
||||||
|
* The `path` parameters are extracted when the {@link ngRoute.$route `$route`} path is matched.
|
||||||
|
*
|
||||||
|
* In case of parameter name collision, `path` params take precedence over `search` params.
|
||||||
|
*
|
||||||
|
* The service guarantees that the identity of the `$routeParams` object will remain unchanged
|
||||||
|
* (but its properties will likely change) even when a route change occurs.
|
||||||
|
*
|
||||||
|
* Note that the `$routeParams` are only updated *after* a route change completes successfully.
|
||||||
|
* This means that you cannot rely on `$routeParams` being correct in route resolve functions.
|
||||||
|
* Instead you can use `$route.current.params` to access the new route's parameters.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js
|
||||||
|
* // Given:
|
||||||
|
* // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
|
||||||
|
* // Route: /Chapter/:chapterId/Section/:sectionId
|
||||||
|
* //
|
||||||
|
* // Then
|
||||||
|
* $routeParams ==> {chapterId:'1', sectionId:'2', search:'moby'}
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
function $RouteParamsProvider() {
|
||||||
|
this.$get = function() { return {}; };
|
||||||
|
}
|
||||||
|
|
||||||
|
ngRouteModule.directive('ngView', ngViewFactory);
|
||||||
|
ngRouteModule.directive('ngView', ngViewFillContentFactory);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc directive
|
||||||
|
* @name ngView
|
||||||
|
* @restrict ECA
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* # Overview
|
||||||
|
* `ngView` is a directive that complements the {@link ngRoute.$route $route} service by
|
||||||
|
* including the rendered template of the current route into the main layout (`index.html`) file.
|
||||||
|
* Every time the current route changes, the included view changes with it according to the
|
||||||
|
* configuration of the `$route` service.
|
||||||
|
*
|
||||||
|
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||||
|
*
|
||||||
|
* @animations
|
||||||
|
* enter - animation is used to bring new content into the browser.
|
||||||
|
* leave - animation is used to animate existing content away.
|
||||||
|
*
|
||||||
|
* The enter and leave animation occur concurrently.
|
||||||
|
*
|
||||||
|
* @scope
|
||||||
|
* @priority 400
|
||||||
|
* @param {string=} onload Expression to evaluate whenever the view updates.
|
||||||
|
*
|
||||||
|
* @param {string=} autoscroll Whether `ngView` should call {@link ng.$anchorScroll
|
||||||
|
* $anchorScroll} to scroll the viewport after the view is updated.
|
||||||
|
*
|
||||||
|
* - If the attribute is not set, disable scrolling.
|
||||||
|
* - If the attribute is set without value, enable scrolling.
|
||||||
|
* - Otherwise enable scrolling only if the `autoscroll` attribute value evaluated
|
||||||
|
* as an expression yields a truthy value.
|
||||||
|
* @example
|
||||||
|
<example name="ngView-directive" module="ngViewExample"
|
||||||
|
deps="angular-route.js;angular-animate.js"
|
||||||
|
animations="true" fixBase="true">
|
||||||
|
<file name="index.html">
|
||||||
|
<div ng-controller="MainCtrl as main">
|
||||||
|
Choose:
|
||||||
|
<a href="Book/Moby">Moby</a> |
|
||||||
|
<a href="Book/Moby/ch/1">Moby: Ch1</a> |
|
||||||
|
<a href="Book/Gatsby">Gatsby</a> |
|
||||||
|
<a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
|
||||||
|
<a href="Book/Scarlet">Scarlet Letter</a><br/>
|
||||||
|
|
||||||
|
<div class="view-animate-container">
|
||||||
|
<div ng-view class="view-animate"></div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<pre>$location.path() = {{main.$location.path()}}</pre>
|
||||||
|
<pre>$route.current.templateUrl = {{main.$route.current.templateUrl}}</pre>
|
||||||
|
<pre>$route.current.params = {{main.$route.current.params}}</pre>
|
||||||
|
<pre>$routeParams = {{main.$routeParams}}</pre>
|
||||||
|
</div>
|
||||||
|
</file>
|
||||||
|
|
||||||
|
<file name="book.html">
|
||||||
|
<div>
|
||||||
|
controller: {{book.name}}<br />
|
||||||
|
Book Id: {{book.params.bookId}}<br />
|
||||||
|
</div>
|
||||||
|
</file>
|
||||||
|
|
||||||
|
<file name="chapter.html">
|
||||||
|
<div>
|
||||||
|
controller: {{chapter.name}}<br />
|
||||||
|
Book Id: {{chapter.params.bookId}}<br />
|
||||||
|
Chapter Id: {{chapter.params.chapterId}}
|
||||||
|
</div>
|
||||||
|
</file>
|
||||||
|
|
||||||
|
<file name="animations.css">
|
||||||
|
.view-animate-container {
|
||||||
|
position:relative;
|
||||||
|
height:100px!important;
|
||||||
|
position:relative;
|
||||||
|
background:white;
|
||||||
|
border:1px solid black;
|
||||||
|
height:40px;
|
||||||
|
overflow:hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-animate {
|
||||||
|
padding:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-animate.ng-enter, .view-animate.ng-leave {
|
||||||
|
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
||||||
|
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
||||||
|
|
||||||
|
display:block;
|
||||||
|
width:100%;
|
||||||
|
border-left:1px solid black;
|
||||||
|
|
||||||
|
position:absolute;
|
||||||
|
top:0;
|
||||||
|
left:0;
|
||||||
|
right:0;
|
||||||
|
bottom:0;
|
||||||
|
padding:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-animate.ng-enter {
|
||||||
|
left:100%;
|
||||||
|
}
|
||||||
|
.view-animate.ng-enter.ng-enter-active {
|
||||||
|
left:0;
|
||||||
|
}
|
||||||
|
.view-animate.ng-leave.ng-leave-active {
|
||||||
|
left:-100%;
|
||||||
|
}
|
||||||
|
</file>
|
||||||
|
|
||||||
|
<file name="script.js">
|
||||||
|
angular.module('ngViewExample', ['ngRoute', 'ngAnimate'])
|
||||||
|
.config(['$routeProvider', '$locationProvider',
|
||||||
|
function($routeProvider, $locationProvider) {
|
||||||
|
$routeProvider
|
||||||
|
.when('/Book/:bookId', {
|
||||||
|
templateUrl: 'book.html',
|
||||||
|
controller: 'BookCtrl',
|
||||||
|
controllerAs: 'book'
|
||||||
|
})
|
||||||
|
.when('/Book/:bookId/ch/:chapterId', {
|
||||||
|
templateUrl: 'chapter.html',
|
||||||
|
controller: 'ChapterCtrl',
|
||||||
|
controllerAs: 'chapter'
|
||||||
|
});
|
||||||
|
|
||||||
|
$locationProvider.html5Mode(true);
|
||||||
|
}])
|
||||||
|
.controller('MainCtrl', ['$route', '$routeParams', '$location',
|
||||||
|
function($route, $routeParams, $location) {
|
||||||
|
this.$route = $route;
|
||||||
|
this.$location = $location;
|
||||||
|
this.$routeParams = $routeParams;
|
||||||
|
}])
|
||||||
|
.controller('BookCtrl', ['$routeParams', function($routeParams) {
|
||||||
|
this.name = "BookCtrl";
|
||||||
|
this.params = $routeParams;
|
||||||
|
}])
|
||||||
|
.controller('ChapterCtrl', ['$routeParams', function($routeParams) {
|
||||||
|
this.name = "ChapterCtrl";
|
||||||
|
this.params = $routeParams;
|
||||||
|
}]);
|
||||||
|
|
||||||
|
</file>
|
||||||
|
|
||||||
|
<file name="protractor.js" type="protractor">
|
||||||
|
it('should load and compile correct template', function() {
|
||||||
|
element(by.linkText('Moby: Ch1')).click();
|
||||||
|
var content = element(by.css('[ng-view]')).getText();
|
||||||
|
expect(content).toMatch(/controller\: ChapterCtrl/);
|
||||||
|
expect(content).toMatch(/Book Id\: Moby/);
|
||||||
|
expect(content).toMatch(/Chapter Id\: 1/);
|
||||||
|
|
||||||
|
element(by.partialLinkText('Scarlet')).click();
|
||||||
|
|
||||||
|
content = element(by.css('[ng-view]')).getText();
|
||||||
|
expect(content).toMatch(/controller\: BookCtrl/);
|
||||||
|
expect(content).toMatch(/Book Id\: Scarlet/);
|
||||||
|
});
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc event
|
||||||
|
* @name ngView#$viewContentLoaded
|
||||||
|
* @eventType emit on the current ngView scope
|
||||||
|
* @description
|
||||||
|
* Emitted every time the ngView content is reloaded.
|
||||||
|
*/
|
||||||
|
ngViewFactory.$inject = ['$route', '$anchorScroll', '$animate'];
|
||||||
|
function ngViewFactory($route, $anchorScroll, $animate) {
|
||||||
|
return {
|
||||||
|
restrict: 'ECA',
|
||||||
|
terminal: true,
|
||||||
|
priority: 400,
|
||||||
|
transclude: 'element',
|
||||||
|
link: function(scope, $element, attr, ctrl, $transclude) {
|
||||||
|
var currentScope,
|
||||||
|
currentElement,
|
||||||
|
previousLeaveAnimation,
|
||||||
|
autoScrollExp = attr.autoscroll,
|
||||||
|
onloadExp = attr.onload || '';
|
||||||
|
|
||||||
|
scope.$on('$routeChangeSuccess', update);
|
||||||
|
update();
|
||||||
|
|
||||||
|
function cleanupLastView() {
|
||||||
|
if (previousLeaveAnimation) {
|
||||||
|
$animate.cancel(previousLeaveAnimation);
|
||||||
|
previousLeaveAnimation = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentScope) {
|
||||||
|
currentScope.$destroy();
|
||||||
|
currentScope = null;
|
||||||
|
}
|
||||||
|
if (currentElement) {
|
||||||
|
previousLeaveAnimation = $animate.leave(currentElement);
|
||||||
|
previousLeaveAnimation.then(function() {
|
||||||
|
previousLeaveAnimation = null;
|
||||||
|
});
|
||||||
|
currentElement = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
var locals = $route.current && $route.current.locals,
|
||||||
|
template = locals && locals.$template;
|
||||||
|
|
||||||
|
if (angular.isDefined(template)) {
|
||||||
|
var newScope = scope.$new();
|
||||||
|
var current = $route.current;
|
||||||
|
|
||||||
|
// Note: This will also link all children of ng-view that were contained in the original
|
||||||
|
// html. If that content contains controllers, ... they could pollute/change the scope.
|
||||||
|
// However, using ng-view on an element with additional content does not make sense...
|
||||||
|
// Note: We can't remove them in the cloneAttchFn of $transclude as that
|
||||||
|
// function is called before linking the content, which would apply child
|
||||||
|
// directives to non existing elements.
|
||||||
|
var clone = $transclude(newScope, function(clone) {
|
||||||
|
$animate.enter(clone, null, currentElement || $element).then(function onNgViewEnter() {
|
||||||
|
if (angular.isDefined(autoScrollExp)
|
||||||
|
&& (!autoScrollExp || scope.$eval(autoScrollExp))) {
|
||||||
|
$anchorScroll();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cleanupLastView();
|
||||||
|
});
|
||||||
|
|
||||||
|
currentElement = clone;
|
||||||
|
currentScope = current.scope = newScope;
|
||||||
|
currentScope.$emit('$viewContentLoaded');
|
||||||
|
currentScope.$eval(onloadExp);
|
||||||
|
} else {
|
||||||
|
cleanupLastView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// This directive is called during the $transclude call of the first `ngView` directive.
|
||||||
|
// It will replace and compile the content of the element with the loaded template.
|
||||||
|
// We need this directive so that the element content is already filled when
|
||||||
|
// the link function of another directive on the same element as ngView
|
||||||
|
// is called.
|
||||||
|
ngViewFillContentFactory.$inject = ['$compile', '$controller', '$route'];
|
||||||
|
function ngViewFillContentFactory($compile, $controller, $route) {
|
||||||
|
return {
|
||||||
|
restrict: 'ECA',
|
||||||
|
priority: -400,
|
||||||
|
link: function(scope, $element) {
|
||||||
|
var current = $route.current,
|
||||||
|
locals = current.locals;
|
||||||
|
|
||||||
|
$element.html(locals.$template);
|
||||||
|
|
||||||
|
var link = $compile($element.contents());
|
||||||
|
|
||||||
|
if (current.controller) {
|
||||||
|
locals.$scope = scope;
|
||||||
|
var controller = $controller(current.controller, locals);
|
||||||
|
if (current.controllerAs) {
|
||||||
|
scope[current.controllerAs] = controller;
|
||||||
|
}
|
||||||
|
$element.data('$ngControllerController', controller);
|
||||||
|
$element.children().data('$ngControllerController', controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
link(scope);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
})(window, window.angular);
|
250
sources/js/angular.min.js
vendored
Normal file
250
sources/js/angular.min.js
vendored
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
/*
|
||||||
|
AngularJS v1.3.4
|
||||||
|
(c) 2010-2014 Google, Inc. http://angularjs.org
|
||||||
|
License: MIT
|
||||||
|
*/
|
||||||
|
(function(U,V,u){'use strict';function z(b){return function(){var a=arguments[0],c;c="["+(b?b+":":"")+a+"] http://errors.angularjs.org/1.3.4/"+(b?b+"/":"")+a;for(a=1;a<arguments.length;a++){c=c+(1==a?"?":"&")+"p"+(a-1)+"=";var d=encodeURIComponent,e;e=arguments[a];e="function"==typeof e?e.toString().replace(/ \{[\s\S]*$/,""):"undefined"==typeof e?"undefined":"string"!=typeof e?JSON.stringify(e):e;c+=d(e)}return Error(c)}}function Ra(b){if(null==b||Sa(b))return!1;var a=b.length;return b.nodeType===
|
||||||
|
na&&a?!0:I(b)||D(b)||0===a||"number"===typeof a&&0<a&&a-1 in b}function r(b,a,c){var d,e;if(b)if(F(b))for(d in b)"prototype"==d||"length"==d||"name"==d||b.hasOwnProperty&&!b.hasOwnProperty(d)||a.call(c,b[d],d,b);else if(D(b)||Ra(b)){var f="object"!==typeof b;d=0;for(e=b.length;d<e;d++)(f||d in b)&&a.call(c,b[d],d,b)}else if(b.forEach&&b.forEach!==r)b.forEach(a,c,b);else for(d in b)b.hasOwnProperty(d)&&a.call(c,b[d],d,b);return b}function Bd(b,a,c){for(var d=Object.keys(b).sort(),e=0;e<d.length;e++)a.call(c,
|
||||||
|
b[d[e]],d[e]);return d}function kc(b){return function(a,c){b(c,a)}}function Cd(){return++kb}function lc(b,a){a?b.$$hashKey=a:delete b.$$hashKey}function C(b){for(var a=b.$$hashKey,c=1,d=arguments.length;c<d;c++){var e=arguments[c];if(e)for(var f=Object.keys(e),g=0,h=f.length;g<h;g++){var k=f[g];b[k]=e[k]}}lc(b,a);return b}function $(b){return parseInt(b,10)}function x(){}function oa(b){return b}function ca(b){return function(){return b}}function G(b){return"undefined"===typeof b}function y(b){return"undefined"!==
|
||||||
|
typeof b}function K(b){return null!==b&&"object"===typeof b}function I(b){return"string"===typeof b}function X(b){return"number"===typeof b}function fa(b){return"[object Date]"===Ja.call(b)}function F(b){return"function"===typeof b}function lb(b){return"[object RegExp]"===Ja.call(b)}function Sa(b){return b&&b.window===b}function Ta(b){return b&&b.$evalAsync&&b.$watch}function Ua(b){return"boolean"===typeof b}function mc(b){return!(!b||!(b.nodeName||b.prop&&b.attr&&b.find))}function Dd(b){var a={};
|
||||||
|
b=b.split(",");var c;for(c=0;c<b.length;c++)a[b[c]]=!0;return a}function ta(b){return R(b.nodeName||b[0]&&b[0].nodeName)}function Va(b,a){var c=b.indexOf(a);0<=c&&b.splice(c,1);return a}function Ca(b,a,c,d){if(Sa(b)||Ta(b))throw Wa("cpws");if(a){if(b===a)throw Wa("cpi");c=c||[];d=d||[];if(K(b)){var e=c.indexOf(b);if(-1!==e)return d[e];c.push(b);d.push(a)}if(D(b))for(var f=a.length=0;f<b.length;f++)e=Ca(b[f],null,c,d),K(b[f])&&(c.push(b[f]),d.push(e)),a.push(e);else{var g=a.$$hashKey;D(a)?a.length=
|
||||||
|
0:r(a,function(b,c){delete a[c]});for(f in b)b.hasOwnProperty(f)&&(e=Ca(b[f],null,c,d),K(b[f])&&(c.push(b[f]),d.push(e)),a[f]=e);lc(a,g)}}else if(a=b)D(b)?a=Ca(b,[],c,d):fa(b)?a=new Date(b.getTime()):lb(b)?(a=new RegExp(b.source,b.toString().match(/[^\/]*$/)[0]),a.lastIndex=b.lastIndex):K(b)&&(e=Object.create(Object.getPrototypeOf(b)),a=Ca(b,e,c,d));return a}function ua(b,a){if(D(b)){a=a||[];for(var c=0,d=b.length;c<d;c++)a[c]=b[c]}else if(K(b))for(c in a=a||{},b)if("$"!==c.charAt(0)||"$"!==c.charAt(1))a[c]=
|
||||||
|
b[c];return a||b}function pa(b,a){if(b===a)return!0;if(null===b||null===a)return!1;if(b!==b&&a!==a)return!0;var c=typeof b,d;if(c==typeof a&&"object"==c)if(D(b)){if(!D(a))return!1;if((c=b.length)==a.length){for(d=0;d<c;d++)if(!pa(b[d],a[d]))return!1;return!0}}else{if(fa(b))return fa(a)?pa(b.getTime(),a.getTime()):!1;if(lb(b)&&lb(a))return b.toString()==a.toString();if(Ta(b)||Ta(a)||Sa(b)||Sa(a)||D(a))return!1;c={};for(d in b)if("$"!==d.charAt(0)&&!F(b[d])){if(!pa(b[d],a[d]))return!1;c[d]=!0}for(d in a)if(!c.hasOwnProperty(d)&&
|
||||||
|
"$"!==d.charAt(0)&&a[d]!==u&&!F(a[d]))return!1;return!0}return!1}function Xa(b,a,c){return b.concat(Ya.call(a,c))}function nc(b,a){var c=2<arguments.length?Ya.call(arguments,2):[];return!F(a)||a instanceof RegExp?a:c.length?function(){return arguments.length?a.apply(b,Xa(c,arguments,0)):a.apply(b,c)}:function(){return arguments.length?a.apply(b,arguments):a.call(b)}}function Ed(b,a){var c=a;"string"===typeof b&&"$"===b.charAt(0)&&"$"===b.charAt(1)?c=u:Sa(a)?c="$WINDOW":a&&V===a?c="$DOCUMENT":Ta(a)&&
|
||||||
|
(c="$SCOPE");return c}function Za(b,a){return"undefined"===typeof b?u:JSON.stringify(b,Ed,a?" ":null)}function oc(b){return I(b)?JSON.parse(b):b}function va(b){b=A(b).clone();try{b.empty()}catch(a){}var c=A("<div>").append(b).html();try{return b[0].nodeType===mb?R(c):c.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+R(b)})}catch(d){return R(c)}}function pc(b){try{return decodeURIComponent(b)}catch(a){}}function qc(b){var a={},c,d;r((b||"").split("&"),function(b){b&&(c=b.replace(/\+/g,
|
||||||
|
"%20").split("="),d=pc(c[0]),y(d)&&(b=y(c[1])?pc(c[1]):!0,Jb.call(a,d)?D(a[d])?a[d].push(b):a[d]=[a[d],b]:a[d]=b))});return a}function Kb(b){var a=[];r(b,function(b,d){D(b)?r(b,function(b){a.push(Da(d,!0)+(!0===b?"":"="+Da(b,!0)))}):a.push(Da(d,!0)+(!0===b?"":"="+Da(b,!0)))});return a.length?a.join("&"):""}function nb(b){return Da(b,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function Da(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,
|
||||||
|
"$").replace(/%2C/gi,",").replace(/%3B/gi,";").replace(/%20/g,a?"%20":"+")}function Fd(b,a){var c,d,e=ob.length;b=A(b);for(d=0;d<e;++d)if(c=ob[d]+a,I(c=b.attr(c)))return c;return null}function Gd(b,a){var c,d,e={};r(ob,function(a){a+="app";!c&&b.hasAttribute&&b.hasAttribute(a)&&(c=b,d=b.getAttribute(a))});r(ob,function(a){a+="app";var e;!c&&(e=b.querySelector("["+a.replace(":","\\:")+"]"))&&(c=e,d=e.getAttribute(a))});c&&(e.strictDi=null!==Fd(c,"strict-di"),a(c,d?[d]:[],e))}function rc(b,a,c){K(c)||
|
||||||
|
(c={});c=C({strictDi:!1},c);var d=function(){b=A(b);if(b.injector()){var d=b[0]===V?"document":va(b);throw Wa("btstrpd",d.replace(/</,"<").replace(/>/,">"));}a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);c.debugInfoEnabled&&a.push(["$compileProvider",function(a){a.debugInfoEnabled(!0)}]);a.unshift("ng");d=Lb(a,c.strictDi);d.invoke(["$rootScope","$rootElement","$compile","$injector",function(a,b,c,d){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return d},e=
|
||||||
|
/^NG_ENABLE_DEBUG_INFO!/,f=/^NG_DEFER_BOOTSTRAP!/;U&&e.test(U.name)&&(c.debugInfoEnabled=!0,U.name=U.name.replace(e,""));if(U&&!f.test(U.name))return d();U.name=U.name.replace(f,"");ha.resumeBootstrap=function(b){r(b,function(b){a.push(b)});d()}}function Hd(){U.name="NG_ENABLE_DEBUG_INFO!"+U.name;U.location.reload()}function Id(b){return ha.element(b).injector().get("$$testability")}function Mb(b,a){a=a||"_";return b.replace(Jd,function(b,d){return(d?a:"")+b.toLowerCase()})}function Kd(){var b;sc||
|
||||||
|
((qa=U.jQuery)&&qa.fn.on?(A=qa,C(qa.fn,{scope:Ka.scope,isolateScope:Ka.isolateScope,controller:Ka.controller,injector:Ka.injector,inheritedData:Ka.inheritedData}),b=qa.cleanData,qa.cleanData=function(a){var c;if(Nb)Nb=!1;else for(var d=0,e;null!=(e=a[d]);d++)(c=qa._data(e,"events"))&&c.$destroy&&qa(e).triggerHandler("$destroy");b(a)}):A=S,ha.element=A,sc=!0)}function Ob(b,a,c){if(!b)throw Wa("areq",a||"?",c||"required");return b}function pb(b,a,c){c&&D(b)&&(b=b[b.length-1]);Ob(F(b),a,"not a function, got "+
|
||||||
|
(b&&"object"===typeof b?b.constructor.name||"Object":typeof b));return b}function La(b,a){if("hasOwnProperty"===b)throw Wa("badname",a);}function tc(b,a,c){if(!a)return b;a=a.split(".");for(var d,e=b,f=a.length,g=0;g<f;g++)d=a[g],b&&(b=(e=b)[d]);return!c&&F(b)?nc(e,b):b}function qb(b){var a=b[0];b=b[b.length-1];var c=[a];do{a=a.nextSibling;if(!a)break;c.push(a)}while(a!==b);return A(c)}function ia(){return Object.create(null)}function Ld(b){function a(a,b,c){return a[b]||(a[b]=c())}var c=z("$injector"),
|
||||||
|
d=z("ng");b=a(b,"angular",Object);b.$$minErr=b.$$minErr||z;return a(b,"module",function(){var b={};return function(f,g,h){if("hasOwnProperty"===f)throw d("badname","module");g&&b.hasOwnProperty(f)&&(b[f]=null);return a(b,f,function(){function a(c,d,e,f){f||(f=b);return function(){f[e||"push"]([c,d,arguments]);return t}}if(!g)throw c("nomod",f);var b=[],d=[],e=[],s=a("$injector","invoke","push",d),t={_invokeQueue:b,_configBlocks:d,_runBlocks:e,requires:g,name:f,provider:a("$provide","provider"),factory:a("$provide",
|
||||||
|
"factory"),service:a("$provide","service"),value:a("$provide","value"),constant:a("$provide","constant","unshift"),animation:a("$animateProvider","register"),filter:a("$filterProvider","register"),controller:a("$controllerProvider","register"),directive:a("$compileProvider","directive"),config:s,run:function(a){e.push(a);return this}};h&&s(h);return t})}})}function Md(b){C(b,{bootstrap:rc,copy:Ca,extend:C,equals:pa,element:A,forEach:r,injector:Lb,noop:x,bind:nc,toJson:Za,fromJson:oc,identity:oa,isUndefined:G,
|
||||||
|
isDefined:y,isString:I,isFunction:F,isObject:K,isNumber:X,isElement:mc,isArray:D,version:Nd,isDate:fa,lowercase:R,uppercase:rb,callbacks:{counter:0},getTestability:Id,$$minErr:z,$$csp:$a,reloadWithDebugInfo:Hd});ab=Ld(U);try{ab("ngLocale")}catch(a){ab("ngLocale",[]).provider("$locale",Od)}ab("ng",["ngLocale"],["$provide",function(a){a.provider({$$sanitizeUri:Pd});a.provider("$compile",uc).directive({a:Qd,input:vc,textarea:vc,form:Rd,script:Sd,select:Td,style:Ud,option:Vd,ngBind:Wd,ngBindHtml:Xd,ngBindTemplate:Yd,
|
||||||
|
ngClass:Zd,ngClassEven:$d,ngClassOdd:ae,ngCloak:be,ngController:ce,ngForm:de,ngHide:ee,ngIf:fe,ngInclude:ge,ngInit:he,ngNonBindable:ie,ngPluralize:je,ngRepeat:ke,ngShow:le,ngStyle:me,ngSwitch:ne,ngSwitchWhen:oe,ngSwitchDefault:pe,ngOptions:qe,ngTransclude:re,ngModel:se,ngList:te,ngChange:ue,pattern:wc,ngPattern:wc,required:xc,ngRequired:xc,minlength:yc,ngMinlength:yc,maxlength:zc,ngMaxlength:zc,ngValue:ve,ngModelOptions:we}).directive({ngInclude:xe}).directive(sb).directive(Ac);a.provider({$anchorScroll:ye,
|
||||||
|
$animate:ze,$browser:Ae,$cacheFactory:Be,$controller:Ce,$document:De,$exceptionHandler:Ee,$filter:Bc,$interpolate:Fe,$interval:Ge,$http:He,$httpBackend:Ie,$location:Je,$log:Ke,$parse:Le,$rootScope:Me,$q:Ne,$$q:Oe,$sce:Pe,$sceDelegate:Qe,$sniffer:Re,$templateCache:Se,$templateRequest:Te,$$testability:Ue,$timeout:Ve,$window:We,$$rAF:Xe,$$asyncCallback:Ye})}])}function bb(b){return b.replace(Ze,function(a,b,d,e){return e?d.toUpperCase():d}).replace($e,"Moz$1")}function Cc(b){b=b.nodeType;return b===
|
||||||
|
na||!b||9===b}function Dc(b,a){var c,d,e=a.createDocumentFragment(),f=[];if(Pb.test(b)){c=c||e.appendChild(a.createElement("div"));d=(af.exec(b)||["",""])[1].toLowerCase();d=ja[d]||ja._default;c.innerHTML=d[1]+b.replace(bf,"<$1></$2>")+d[2];for(d=d[0];d--;)c=c.lastChild;f=Xa(f,c.childNodes);c=e.firstChild;c.textContent=""}else f.push(a.createTextNode(b));e.textContent="";e.innerHTML="";r(f,function(a){e.appendChild(a)});return e}function S(b){if(b instanceof S)return b;var a;I(b)&&(b=P(b),a=!0);if(!(this instanceof
|
||||||
|
S)){if(a&&"<"!=b.charAt(0))throw Qb("nosel");return new S(b)}if(a){a=V;var c;b=(c=cf.exec(b))?[a.createElement(c[1])]:(c=Dc(b,a))?c.childNodes:[]}Ec(this,b)}function Rb(b){return b.cloneNode(!0)}function tb(b,a){a||ub(b);if(b.querySelectorAll)for(var c=b.querySelectorAll("*"),d=0,e=c.length;d<e;d++)ub(c[d])}function Fc(b,a,c,d){if(y(d))throw Qb("offargs");var e=(d=vb(b))&&d.events,f=d&&d.handle;if(f)if(a)r(a.split(" "),function(a){if(y(c)){var d=e[a];Va(d||[],c);if(d&&0<d.length)return}b.removeEventListener(a,
|
||||||
|
f,!1);delete e[a]});else for(a in e)"$destroy"!==a&&b.removeEventListener(a,f,!1),delete e[a]}function ub(b,a){var c=b.ng339,d=c&&wb[c];d&&(a?delete d.data[a]:(d.handle&&(d.events.$destroy&&d.handle({},"$destroy"),Fc(b)),delete wb[c],b.ng339=u))}function vb(b,a){var c=b.ng339,c=c&&wb[c];a&&!c&&(b.ng339=c=++df,c=wb[c]={events:{},data:{},handle:u});return c}function Sb(b,a,c){if(Cc(b)){var d=y(c),e=!d&&a&&!K(a),f=!a;b=(b=vb(b,!e))&&b.data;if(d)b[a]=c;else{if(f)return b;if(e)return b&&b[a];C(b,a)}}}
|
||||||
|
function Tb(b,a){return b.getAttribute?-1<(" "+(b.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ").indexOf(" "+a+" "):!1}function Ub(b,a){a&&b.setAttribute&&r(a.split(" "),function(a){b.setAttribute("class",P((" "+(b.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ").replace(" "+P(a)+" "," ")))})}function Vb(b,a){if(a&&b.setAttribute){var c=(" "+(b.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ");r(a.split(" "),function(a){a=P(a);-1===c.indexOf(" "+a+" ")&&(c+=a+" ")});b.setAttribute("class",
|
||||||
|
P(c))}}function Ec(b,a){if(a)if(a.nodeType)b[b.length++]=a;else{var c=a.length;if("number"===typeof c&&a.window!==a){if(c)for(var d=0;d<c;d++)b[b.length++]=a[d]}else b[b.length++]=a}}function Gc(b,a){return xb(b,"$"+(a||"ngController")+"Controller")}function xb(b,a,c){9==b.nodeType&&(b=b.documentElement);for(a=D(a)?a:[a];b;){for(var d=0,e=a.length;d<e;d++)if((c=A.data(b,a[d]))!==u)return c;b=b.parentNode||11===b.nodeType&&b.host}}function Hc(b){for(tb(b,!0);b.firstChild;)b.removeChild(b.firstChild)}
|
||||||
|
function Ic(b,a){a||tb(b);var c=b.parentNode;c&&c.removeChild(b)}function ef(b,a){a=a||U;if("complete"===a.document.readyState)a.setTimeout(b);else A(a).on("load",b)}function Jc(b,a){var c=yb[a.toLowerCase()];return c&&Kc[ta(b)]&&c}function ff(b,a){var c=b.nodeName;return("INPUT"===c||"TEXTAREA"===c)&&Lc[a]}function gf(b,a){var c=function(c,e){c.isDefaultPrevented=function(){return c.defaultPrevented};var f=a[e||c.type],g=f?f.length:0;if(g){if(G(c.immediatePropagationStopped)){var h=c.stopImmediatePropagation;
|
||||||
|
c.stopImmediatePropagation=function(){c.immediatePropagationStopped=!0;c.stopPropagation&&c.stopPropagation();h&&h.call(c)}}c.isImmediatePropagationStopped=function(){return!0===c.immediatePropagationStopped};1<g&&(f=ua(f));for(var k=0;k<g;k++)c.isImmediatePropagationStopped()||f[k].call(b,c)}};c.elem=b;return c}function Ma(b,a){var c=b&&b.$$hashKey;if(c)return"function"===typeof c&&(c=b.$$hashKey()),c;c=typeof b;return c="function"==c||"object"==c&&null!==b?b.$$hashKey=c+":"+(a||Cd)():c+":"+b}function cb(b,
|
||||||
|
a){if(a){var c=0;this.nextUid=function(){return++c}}r(b,this.put,this)}function hf(b){return(b=b.toString().replace(Mc,"").match(Nc))?"function("+(b[1]||"").replace(/[\s\r\n]+/," ")+")":"fn"}function Wb(b,a,c){var d;if("function"===typeof b){if(!(d=b.$inject)){d=[];if(b.length){if(a)throw I(c)&&c||(c=b.name||hf(b)),Ea("strictdi",c);a=b.toString().replace(Mc,"");a=a.match(Nc);r(a[1].split(jf),function(a){a.replace(kf,function(a,b,c){d.push(c)})})}b.$inject=d}}else D(b)?(a=b.length-1,pb(b[a],"fn"),
|
||||||
|
d=b.slice(0,a)):pb(b,"fn",!0);return d}function Lb(b,a){function c(a){return function(b,c){if(K(b))r(b,kc(a));else return a(b,c)}}function d(a,b){La(a,"service");if(F(b)||D(b))b=s.instantiate(b);if(!b.$get)throw Ea("pget",a);return p[a+"Provider"]=b}function e(a,b){return function(){var c=q.invoke(b,this,u,a);if(G(c))throw Ea("undef",a);return c}}function f(a,b,c){return d(a,{$get:!1!==c?e(a,b):b})}function g(a){var b=[],c;r(a,function(a){function d(a){var b,c;b=0;for(c=a.length;b<c;b++){var e=a[b],
|
||||||
|
f=s.get(e[0]);f[e[1]].apply(f,e[2])}}if(!m.get(a)){m.put(a,!0);try{I(a)?(c=ab(a),b=b.concat(g(c.requires)).concat(c._runBlocks),d(c._invokeQueue),d(c._configBlocks)):F(a)?b.push(s.invoke(a)):D(a)?b.push(s.invoke(a)):pb(a,"module")}catch(e){throw D(a)&&(a=a[a.length-1]),e.message&&e.stack&&-1==e.stack.indexOf(e.message)&&(e=e.message+"\n"+e.stack),Ea("modulerr",a,e.stack||e.message||e);}}});return b}function h(b,c){function d(a){if(b.hasOwnProperty(a)){if(b[a]===k)throw Ea("cdep",a+" <- "+l.join(" <- "));
|
||||||
|
return b[a]}try{return l.unshift(a),b[a]=k,b[a]=c(a)}catch(e){throw b[a]===k&&delete b[a],e;}finally{l.shift()}}function e(b,c,f,g){"string"===typeof f&&(g=f,f=null);var k=[];g=Wb(b,a,g);var h,l,q;l=0;for(h=g.length;l<h;l++){q=g[l];if("string"!==typeof q)throw Ea("itkn",q);k.push(f&&f.hasOwnProperty(q)?f[q]:d(q))}D(b)&&(b=b[h]);return b.apply(c,k)}return{invoke:e,instantiate:function(a,b,c){var d=Object.create((D(a)?a[a.length-1]:a).prototype);a=e(a,d,b,c);return K(a)||F(a)?a:d},get:d,annotate:Wb,
|
||||||
|
has:function(a){return p.hasOwnProperty(a+"Provider")||b.hasOwnProperty(a)}}}a=!0===a;var k={},l=[],m=new cb([],!0),p={$provide:{provider:c(d),factory:c(f),service:c(function(a,b){return f(a,["$injector",function(a){return a.instantiate(b)}])}),value:c(function(a,b){return f(a,ca(b),!1)}),constant:c(function(a,b){La(a,"constant");p[a]=b;t[a]=b}),decorator:function(a,b){var c=s.get(a+"Provider"),d=c.$get;c.$get=function(){var a=q.invoke(d,c);return q.invoke(b,null,{$delegate:a})}}}},s=p.$injector=
|
||||||
|
h(p,function(){throw Ea("unpr",l.join(" <- "));}),t={},q=t.$injector=h(t,function(a){var b=s.get(a+"Provider");return q.invoke(b.$get,b,u,a)});r(g(b),function(a){q.invoke(a||x)});return q}function ye(){var b=!0;this.disableAutoScrolling=function(){b=!1};this.$get=["$window","$location","$rootScope",function(a,c,d){function e(a){var b=null;Array.prototype.some.call(a,function(a){if("a"===ta(a))return b=a,!0});return b}function f(b){if(b){b.scrollIntoView();var c;c=g.yOffset;F(c)?c=c():mc(c)?(c=c[0],
|
||||||
|
c="fixed"!==a.getComputedStyle(c).position?0:c.getBoundingClientRect().bottom):X(c)||(c=0);c&&(b=b.getBoundingClientRect().top,a.scrollBy(0,b-c))}else a.scrollTo(0,0)}function g(){var a=c.hash(),b;a?(b=h.getElementById(a))?f(b):(b=e(h.getElementsByName(a)))?f(b):"top"===a&&f(null):f(null)}var h=a.document;b&&d.$watch(function(){return c.hash()},function(a,b){a===b&&""===a||ef(function(){d.$evalAsync(g)})});return g}]}function Ye(){this.$get=["$$rAF","$timeout",function(b,a){return b.supported?function(a){return b(a)}:
|
||||||
|
function(b){return a(b,0,!1)}}]}function lf(b,a,c,d){function e(a){try{a.apply(null,Ya.call(arguments,1))}finally{if(v--,0===v)for(;w.length;)try{w.pop()()}catch(b){c.error(b)}}}function f(a,b){(function ya(){r(O,function(a){a()});E=b(ya,a)})()}function g(){h();k()}function h(){H=b.history.state;H=G(H)?null:H;pa(H,Q)&&(H=Q);Q=H}function k(){if(B!==m.url()||M!==H)B=m.url(),M=H,r(W,function(a){a(m.url(),H)})}function l(a){try{return decodeURIComponent(a)}catch(b){return a}}var m=this,p=a[0],s=b.location,
|
||||||
|
t=b.history,q=b.setTimeout,N=b.clearTimeout,n={};m.isMock=!1;var v=0,w=[];m.$$completeOutstandingRequest=e;m.$$incOutstandingRequestCount=function(){v++};m.notifyWhenNoOutstandingRequests=function(a){r(O,function(a){a()});0===v?a():w.push(a)};var O=[],E;m.addPollFn=function(a){G(E)&&f(100,q);O.push(a);return a};var H,M,B=s.href,ea=a.find("base"),L=null;h();M=H;m.url=function(a,c,e){G(e)&&(e=null);s!==b.location&&(s=b.location);t!==b.history&&(t=b.history);if(a){var f=M===e;if(B===a&&(!d.history||
|
||||||
|
f))return m;var g=B&&Fa(B)===Fa(a);B=a;M=e;!d.history||g&&f?(g||(L=a),c?s.replace(a):s.href=a):(t[c?"replaceState":"pushState"](e,"",a),h(),M=H);return m}return L||s.href.replace(/%27/g,"'")};m.state=function(){return H};var W=[],ba=!1,Q=null;m.onUrlChange=function(a){if(!ba){if(d.history)A(b).on("popstate",g);A(b).on("hashchange",g);ba=!0}W.push(a);return a};m.$$checkUrlChange=k;m.baseHref=function(){var a=ea.attr("href");return a?a.replace(/^(https?\:)?\/\/[^\/]*/,""):""};var aa={},y="",da=m.baseHref();
|
||||||
|
m.cookies=function(a,b){var d,e,f,g;if(a)b===u?p.cookie=encodeURIComponent(a)+"=;path="+da+";expires=Thu, 01 Jan 1970 00:00:00 GMT":I(b)&&(d=(p.cookie=encodeURIComponent(a)+"="+encodeURIComponent(b)+";path="+da).length+1,4096<d&&c.warn("Cookie '"+a+"' possibly not set or overflowed because it was too large ("+d+" > 4096 bytes)!"));else{if(p.cookie!==y)for(y=p.cookie,d=y.split("; "),aa={},f=0;f<d.length;f++)e=d[f],g=e.indexOf("="),0<g&&(a=l(e.substring(0,g)),aa[a]===u&&(aa[a]=l(e.substring(g+1))));
|
||||||
|
return aa}};m.defer=function(a,b){var c;v++;c=q(function(){delete n[c];e(a)},b||0);n[c]=!0;return c};m.defer.cancel=function(a){return n[a]?(delete n[a],N(a),e(x),!0):!1}}function Ae(){this.$get=["$window","$log","$sniffer","$document",function(b,a,c,d){return new lf(b,d,a,c)}]}function Be(){this.$get=function(){function b(b,d){function e(a){a!=p&&(s?s==a&&(s=a.n):s=a,f(a.n,a.p),f(a,p),p=a,p.n=null)}function f(a,b){a!=b&&(a&&(a.p=b),b&&(b.n=a))}if(b in a)throw z("$cacheFactory")("iid",b);var g=0,
|
||||||
|
h=C({},d,{id:b}),k={},l=d&&d.capacity||Number.MAX_VALUE,m={},p=null,s=null;return a[b]={put:function(a,b){if(l<Number.MAX_VALUE){var c=m[a]||(m[a]={key:a});e(c)}if(!G(b))return a in k||g++,k[a]=b,g>l&&this.remove(s.key),b},get:function(a){if(l<Number.MAX_VALUE){var b=m[a];if(!b)return;e(b)}return k[a]},remove:function(a){if(l<Number.MAX_VALUE){var b=m[a];if(!b)return;b==p&&(p=b.p);b==s&&(s=b.n);f(b.n,b.p);delete m[a]}delete k[a];g--},removeAll:function(){k={};g=0;m={};p=s=null},destroy:function(){m=
|
||||||
|
h=k=null;delete a[b]},info:function(){return C({},h,{size:g})}}}var a={};b.info=function(){var b={};r(a,function(a,e){b[e]=a.info()});return b};b.get=function(b){return a[b]};return b}}function Se(){this.$get=["$cacheFactory",function(b){return b("templates")}]}function uc(b,a){function c(a,b){var c=/^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/,d={};r(a,function(a,e){var f=a.match(c);if(!f)throw ka("iscp",b,e,a);d[e]={mode:f[1][0],collection:"*"===f[2],optional:"?"===f[3],attrName:f[4]||e}});return d}var d=
|
||||||
|
{},e=/^\s*directive\:\s*([\w\-]+)\s+(.*)$/,f=/(([\w\-]+)(?:\:([^;]+))?;?)/,g=Dd("ngSrc,ngSrcset,src,srcset"),h=/^(?:(\^\^?)?(\?)?(\^\^?)?)?/,k=/^(on[a-z]+|formaction)$/;this.directive=function p(a,e){La(a,"directive");I(a)?(Ob(e,"directiveFactory"),d.hasOwnProperty(a)||(d[a]=[],b.factory(a+"Directive",["$injector","$exceptionHandler",function(b,e){var f=[];r(d[a],function(d,g){try{var h=b.invoke(d);F(h)?h={compile:ca(h)}:!h.compile&&h.link&&(h.compile=ca(h.link));h.priority=h.priority||0;h.index=
|
||||||
|
g;h.name=h.name||a;h.require=h.require||h.controller&&h.name;h.restrict=h.restrict||"EA";K(h.scope)&&(h.$$isolateBindings=c(h.scope,h.name));f.push(h)}catch(k){e(k)}});return f}])),d[a].push(e)):r(a,kc(p));return this};this.aHrefSanitizationWhitelist=function(b){return y(b)?(a.aHrefSanitizationWhitelist(b),this):a.aHrefSanitizationWhitelist()};this.imgSrcSanitizationWhitelist=function(b){return y(b)?(a.imgSrcSanitizationWhitelist(b),this):a.imgSrcSanitizationWhitelist()};var l=!0;this.debugInfoEnabled=
|
||||||
|
function(a){return y(a)?(l=a,this):l};this.$get=["$injector","$interpolate","$exceptionHandler","$templateRequest","$parse","$controller","$rootScope","$document","$sce","$animate","$$sanitizeUri",function(a,b,c,q,N,n,v,w,O,E,H){function M(a,b){try{a.addClass(b)}catch(c){}}function B(a,b,c,d,e){a instanceof A||(a=A(a));r(a,function(b,c){b.nodeType==mb&&b.nodeValue.match(/\S+/)&&(a[c]=A(b).wrap("<span></span>").parent()[0])});var f=ea(a,b,a,c,d,e);B.$$addScopeClass(a);var g=null;return function(b,
|
||||||
|
c,d){Ob(b,"scope");d=d||{};var e=d.parentBoundTranscludeFn,h=d.transcludeControllers;d=d.futureParentElement;e&&e.$$boundTransclude&&(e=e.$$boundTransclude);g||(g=(d=d&&d[0])?"foreignobject"!==ta(d)&&d.toString().match(/SVG/)?"svg":"html":"html");d="html"!==g?A(U(g,A("<div>").append(a).html())):c?Ka.clone.call(a):a;if(h)for(var k in h)d.data("$"+k+"Controller",h[k].instance);B.$$addScopeInfo(d,b);c&&c(d,b);f&&f(b,d,d,e);return d}}function ea(a,b,c,d,e,f){function g(a,c,d,e){var f,k,l,q,s,n,w;if(p)for(w=
|
||||||
|
Array(c.length),q=0;q<h.length;q+=3)f=h[q],w[f]=c[f];else w=c;q=0;for(s=h.length;q<s;)k=w[h[q++]],c=h[q++],f=h[q++],c?(c.scope?(l=a.$new(),B.$$addScopeInfo(A(k),l)):l=a,n=c.transcludeOnThisElement?L(a,c.transclude,e,c.elementTranscludeOnThisElement):!c.templateOnThisElement&&e?e:!e&&b?L(a,b):null,c(f,l,k,d,n)):f&&f(a,k.childNodes,u,e)}for(var h=[],k,l,q,s,p,n=0;n<a.length;n++){k=new X;l=W(a[n],[],k,0===n?d:u,e);(f=l.length?aa(l,a[n],k,b,c,null,[],[],f):null)&&f.scope&&B.$$addScopeClass(k.$$element);
|
||||||
|
k=f&&f.terminal||!(q=a[n].childNodes)||!q.length?null:ea(q,f?(f.transcludeOnThisElement||!f.templateOnThisElement)&&f.transclude:b);if(f||k)h.push(n,f,k),s=!0,p=p||f;f=null}return s?g:null}function L(a,b,c,d){return function(d,e,f,g,h){d||(d=a.$new(!1,h),d.$$transcluded=!0);return b(d,e,{parentBoundTranscludeFn:c,transcludeControllers:f,futureParentElement:g})}}function W(b,c,g,h,k){var l=g.$attr,q;switch(b.nodeType){case na:da(c,wa(ta(b)),"E",h,k);for(var s,n,w,N=b.attributes,t=0,O=N&&N.length;t<
|
||||||
|
O;t++){var H=!1,v=!1;s=N[t];q=s.name;s=P(s.value);n=wa(q);if(w=za.test(n))q=Mb(n.substr(6),"-");var M=n.replace(/(Start|End)$/,""),E;a:{var B=M;if(d.hasOwnProperty(B)){E=void 0;for(var B=a.get(B+"Directive"),W=0,r=B.length;W<r;W++)if(E=B[W],E.multiElement){E=!0;break a}}E=!1}E&&n===M+"Start"&&(H=q,v=q.substr(0,q.length-5)+"end",q=q.substr(0,q.length-6));n=wa(q.toLowerCase());l[n]=q;if(w||!g.hasOwnProperty(n))g[n]=s,Jc(b,n)&&(g[n]=!0);S(b,c,s,n,w);da(c,n,"A",h,k,H,v)}b=b.className;if(I(b)&&""!==b)for(;q=
|
||||||
|
f.exec(b);)n=wa(q[2]),da(c,n,"C",h,k)&&(g[n]=P(q[3])),b=b.substr(q.index+q[0].length);break;case mb:T(c,b.nodeValue);break;case 8:try{if(q=e.exec(b.nodeValue))n=wa(q[1]),da(c,n,"M",h,k)&&(g[n]=P(q[2]))}catch(Q){}}c.sort(z);return c}function ba(a,b,c){var d=[],e=0;if(b&&a.hasAttribute&&a.hasAttribute(b)){do{if(!a)throw ka("uterdir",b,c);a.nodeType==na&&(a.hasAttribute(b)&&e++,a.hasAttribute(c)&&e--);d.push(a);a=a.nextSibling}while(0<e)}else d.push(a);return A(d)}function Q(a,b,c){return function(d,
|
||||||
|
e,f,g,h){e=ba(e[0],b,c);return a(d,e,f,g,h)}}function aa(a,d,e,f,g,k,l,q,p){function w(a,b,c,d){if(a){c&&(a=Q(a,c,d));a.require=J.require;a.directiveName=ga;if(L===J||J.$$isolateScope)a=Y(a,{isolateScope:!0});l.push(a)}if(b){c&&(b=Q(b,c,d));b.require=J.require;b.directiveName=ga;if(L===J||J.$$isolateScope)b=Y(b,{isolateScope:!0});q.push(b)}}function O(a,b,c,d){var e,f="data",g=!1,k=c,l;if(I(b)){l=b.match(h);b=b.substring(l[0].length);l[3]&&(l[1]?l[3]=null:l[1]=l[3]);"^"===l[1]?f="inheritedData":"^^"===
|
||||||
|
l[1]&&(f="inheritedData",k=c.parent());"?"===l[2]&&(g=!0);e=null;d&&"data"===f&&(e=d[b])&&(e=e.instance);e=e||k[f]("$"+b+"Controller");if(!e&&!g)throw ka("ctreq",b,a);return e||null}D(b)&&(e=[],r(b,function(b){e.push(O(a,b,c,d))}));return e}function H(a,c,f,g,h){function k(a,b,c){var d;Ta(a)||(c=b,b=a,a=u);C&&(d=M);c||(c=C?W.parent():W);return h(a,b,d,c,Xb)}var p,w,t,v,M,db,W,Q;d===f?(Q=e,W=e.$$element):(W=A(f),Q=new X(W,e));L&&(v=c.$new(!0));h&&(db=k,db.$$boundTransclude=h);E&&(ea={},M={},r(E,function(a){var b=
|
||||||
|
{$scope:a===L||a.$$isolateScope?v:c,$element:W,$attrs:Q,$transclude:db};t=a.controller;"@"==t&&(t=Q[a.name]);b=n(t,b,!0,a.controllerAs);M[a.name]=b;C||W.data("$"+a.name+"Controller",b.instance);ea[a.name]=b}));if(L){B.$$addScopeInfo(W,v,!0,!(aa&&(aa===L||aa===L.$$originalDirective)));B.$$addScopeClass(W,!0);g=ea&&ea[L.name];var ba=v;g&&g.identifier&&!0===L.bindToController&&(ba=g.instance);r(v.$$isolateBindings=L.$$isolateBindings,function(a,d){var e=a.attrName,f=a.optional,g,h,k,l;switch(a.mode){case "@":Q.$observe(e,
|
||||||
|
function(a){ba[d]=a});Q.$$observers[e].$$scope=c;Q[e]&&(ba[d]=b(Q[e])(c));break;case "=":if(f&&!Q[e])break;h=N(Q[e]);l=h.literal?pa:function(a,b){return a===b||a!==a&&b!==b};k=h.assign||function(){g=ba[d]=h(c);throw ka("nonassign",Q[e],L.name);};g=ba[d]=h(c);f=function(a){l(a,ba[d])||(l(a,g)?k(c,a=ba[d]):ba[d]=a);return g=a};f.$stateful=!0;f=a.collection?c.$watchCollection(Q[e],f):c.$watch(N(Q[e],f),null,h.literal);v.$on("$destroy",f);break;case "&":h=N(Q[e]),ba[d]=function(a){return h(c,a)}}})}ea&&
|
||||||
|
(r(ea,function(a){a()}),ea=null);g=0;for(p=l.length;g<p;g++)w=l[g],Z(w,w.isolateScope?v:c,W,Q,w.require&&O(w.directiveName,w.require,W,M),db);var Xb=c;L&&(L.template||null===L.templateUrl)&&(Xb=v);a&&a(Xb,f.childNodes,u,h);for(g=q.length-1;0<=g;g--)w=q[g],Z(w,w.isolateScope?v:c,W,Q,w.require&&O(w.directiveName,w.require,W,M),db)}p=p||{};for(var v=-Number.MAX_VALUE,M,E=p.controllerDirectives,ea,L=p.newIsolateScopeDirective,aa=p.templateDirective,da=p.nonTlbTranscludeDirective,x=!1,Na=!1,C=p.hasElementTranscludeDirective,
|
||||||
|
T=e.$$element=A(d),J,ga,z,Ga=f,R,S=0,za=a.length;S<za;S++){J=a[S];var zb=J.$$start,$=J.$$end;zb&&(T=ba(d,zb,$));z=u;if(v>J.priority)break;if(z=J.scope)J.templateUrl||(K(z)?(ya("new/isolated scope",L||M,J,T),L=J):ya("new/isolated scope",L,J,T)),M=M||J;ga=J.name;!J.templateUrl&&J.controller&&(z=J.controller,E=E||{},ya("'"+ga+"' controller",E[ga],J,T),E[ga]=J);if(z=J.transclude)x=!0,J.$$tlb||(ya("transclusion",da,J,T),da=J),"element"==z?(C=!0,v=J.priority,z=T,T=e.$$element=A(V.createComment(" "+ga+": "+
|
||||||
|
e[ga]+" ")),d=T[0],Ab(g,Ya.call(z,0),d),Ga=B(z,f,v,k&&k.name,{nonTlbTranscludeDirective:da})):(z=A(Rb(d)).contents(),T.empty(),Ga=B(z,f));if(J.template)if(Na=!0,ya("template",aa,J,T),aa=J,z=F(J.template)?J.template(T,e):J.template,z=Pc(z),J.replace){k=J;z=Pb.test(z)?Qc(U(J.templateNamespace,P(z))):[];d=z[0];if(1!=z.length||d.nodeType!==na)throw ka("tplrt",ga,"");Ab(g,T,d);za={$attr:{}};z=W(d,[],za);var mf=a.splice(S+1,a.length-(S+1));L&&y(z);a=a.concat(z).concat(mf);Oc(e,za);za=a.length}else T.html(z);
|
||||||
|
if(J.templateUrl)Na=!0,ya("template",aa,J,T),aa=J,J.replace&&(k=J),H=G(a.splice(S,a.length-S),T,e,g,x&&Ga,l,q,{controllerDirectives:E,newIsolateScopeDirective:L,templateDirective:aa,nonTlbTranscludeDirective:da}),za=a.length;else if(J.compile)try{R=J.compile(T,e,Ga),F(R)?w(null,R,zb,$):R&&w(R.pre,R.post,zb,$)}catch(ca){c(ca,va(T))}J.terminal&&(H.terminal=!0,v=Math.max(v,J.priority))}H.scope=M&&!0===M.scope;H.transcludeOnThisElement=x;H.elementTranscludeOnThisElement=C;H.templateOnThisElement=Na;H.transclude=
|
||||||
|
Ga;p.hasElementTranscludeDirective=C;return H}function y(a){for(var b=0,c=a.length;b<c;b++){var d=b,e;e=C(Object.create(a[b]),{$$isolateScope:!0});a[d]=e}}function da(b,e,f,g,h,k,l){if(e===h)return null;h=null;if(d.hasOwnProperty(e)){var q;e=a.get(e+"Directive");for(var s=0,n=e.length;s<n;s++)try{if(q=e[s],(g===u||g>q.priority)&&-1!=q.restrict.indexOf(f)){if(k){var w={$$start:k,$$end:l};q=C(Object.create(q),w)}b.push(q);h=q}}catch(N){c(N)}}return h}function Oc(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;
|
||||||
|
r(a,function(d,e){"$"!=e.charAt(0)&&(b[e]&&b[e]!==d&&(d+=("style"===e?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});r(b,function(b,f){"class"==f?(M(e,b),a["class"]=(a["class"]?a["class"]+" ":"")+b):"style"==f?(e.attr("style",e.attr("style")+";"+b),a.style=(a.style?a.style+";":"")+b):"$"==f.charAt(0)||a.hasOwnProperty(f)||(a[f]=b,d[f]=c[f])})}function G(a,b,c,d,e,f,g,h){var k=[],l,s,p=b[0],n=a.shift(),w=C({},n,{templateUrl:null,transclude:null,replace:null,$$originalDirective:n}),N=F(n.templateUrl)?n.templateUrl(b,
|
||||||
|
c):n.templateUrl,t=n.templateNamespace;b.empty();q(O.getTrustedResourceUrl(N)).then(function(q){var v,O;q=Pc(q);if(n.replace){q=Pb.test(q)?Qc(U(t,P(q))):[];v=q[0];if(1!=q.length||v.nodeType!==na)throw ka("tplrt",n.name,N);q={$attr:{}};Ab(d,b,v);var H=W(v,[],q);K(n.scope)&&y(H);a=H.concat(a);Oc(c,q)}else v=p,b.html(q);a.unshift(w);l=aa(a,v,c,e,b,n,f,g,h);r(d,function(a,c){a==v&&(d[c]=b[0])});for(s=ea(b[0].childNodes,e);k.length;){q=k.shift();O=k.shift();var E=k.shift(),B=k.shift(),H=b[0];if(!q.$$destroyed){if(O!==
|
||||||
|
p){var Q=O.className;h.hasElementTranscludeDirective&&n.replace||(H=Rb(v));Ab(E,A(O),H);M(A(H),Q)}O=l.transcludeOnThisElement?L(q,l.transclude,B):B;l(s,q,H,d,O)}}k=null});return function(a,b,c,d,e){a=e;b.$$destroyed||(k?k.push(b,c,d,a):(l.transcludeOnThisElement&&(a=L(b,l.transclude,e)),l(s,b,c,d,a)))}}function z(a,b){var c=b.priority-a.priority;return 0!==c?c:a.name!==b.name?a.name<b.name?-1:1:a.index-b.index}function ya(a,b,c,d){if(b)throw ka("multidir",b.name,c.name,a,va(d));}function T(a,c){var d=
|
||||||
|
b(c,!0);d&&a.push({priority:0,compile:function(a){a=a.parent();var b=!!a.length;b&&B.$$addBindingClass(a);return function(a,c){var e=c.parent();b||B.$$addBindingClass(e);B.$$addBindingInfo(e,d.expressions);a.$watch(d,function(a){c[0].nodeValue=a})}}})}function U(a,b){a=R(a||"html");switch(a){case "svg":case "math":var c=V.createElement("div");c.innerHTML="<"+a+">"+b+"</"+a+">";return c.childNodes[0].childNodes;default:return b}}function Ga(a,b){if("srcdoc"==b)return O.HTML;var c=ta(a);if("xlinkHref"==
|
||||||
|
b||"form"==c&&"action"==b||"img"!=c&&("src"==b||"ngSrc"==b))return O.RESOURCE_URL}function S(a,c,d,e,f){var h=b(d,!0);if(h){if("multiple"===e&&"select"===ta(a))throw ka("selmulti",va(a));c.push({priority:100,compile:function(){return{pre:function(c,d,l){d=l.$$observers||(l.$$observers={});if(k.test(e))throw ka("nodomevents");l[e]&&(h=b(l[e],!0,Ga(a,e),g[e]||f))&&(l[e]=h(c),(d[e]||(d[e]=[])).$$inter=!0,(l.$$observers&&l.$$observers[e].$$scope||c).$watch(h,function(a,b){"class"===e&&a!=b?l.$updateClass(a,
|
||||||
|
b):l.$set(e,a)}))}}}})}}function Ab(a,b,c){var d=b[0],e=b.length,f=d.parentNode,g,h;if(a)for(g=0,h=a.length;g<h;g++)if(a[g]==d){a[g++]=c;h=g+e-1;for(var k=a.length;g<k;g++,h++)h<k?a[g]=a[h]:delete a[g];a.length-=e-1;a.context===d&&(a.context=c);break}f&&f.replaceChild(c,d);a=V.createDocumentFragment();a.appendChild(d);A(c).data(A(d).data());qa?(Nb=!0,qa.cleanData([d])):delete A.cache[d[A.expando]];d=1;for(e=b.length;d<e;d++)f=b[d],A(f).remove(),a.appendChild(f),delete b[d];b[0]=c;b.length=1}function Y(a,
|
||||||
|
b){return C(function(){return a.apply(null,arguments)},a,b)}function Z(a,b,d,e,f,g){try{a(b,d,e,f,g)}catch(h){c(h,va(d))}}var X=function(a,b){if(b){var c=Object.keys(b),d,e,f;d=0;for(e=c.length;d<e;d++)f=c[d],this[f]=b[f]}else this.$attr={};this.$$element=a};X.prototype={$normalize:wa,$addClass:function(a){a&&0<a.length&&E.addClass(this.$$element,a)},$removeClass:function(a){a&&0<a.length&&E.removeClass(this.$$element,a)},$updateClass:function(a,b){var c=Rc(a,b);c&&c.length&&E.addClass(this.$$element,
|
||||||
|
c);(c=Rc(b,a))&&c.length&&E.removeClass(this.$$element,c)},$set:function(a,b,d,e){var f=this.$$element[0],g=Jc(f,a),h=ff(f,a),f=a;g?(this.$$element.prop(a,b),e=g):h&&(this[h]=b,f=h);this[a]=b;e?this.$attr[a]=e:(e=this.$attr[a])||(this.$attr[a]=e=Mb(a,"-"));g=ta(this.$$element);if("a"===g&&"href"===a||"img"===g&&"src"===a)this[a]=b=H(b,"src"===a);else if("img"===g&&"srcset"===a){for(var g="",h=P(b),k=/(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/,k=/\s/.test(h)?k:/(,)/,h=h.split(k),k=Math.floor(h.length/2),
|
||||||
|
l=0;l<k;l++)var q=2*l,g=g+H(P(h[q]),!0),g=g+(" "+P(h[q+1]));h=P(h[2*l]).split(/\s/);g+=H(P(h[0]),!0);2===h.length&&(g+=" "+P(h[1]));this[a]=b=g}!1!==d&&(null===b||b===u?this.$$element.removeAttr(e):this.$$element.attr(e,b));(a=this.$$observers)&&r(a[f],function(a){try{a(b)}catch(d){c(d)}})},$observe:function(a,b){var c=this,d=c.$$observers||(c.$$observers=ia()),e=d[a]||(d[a]=[]);e.push(b);v.$evalAsync(function(){!e.$$inter&&c.hasOwnProperty(a)&&b(c[a])});return function(){Va(e,b)}}};var Na=b.startSymbol(),
|
||||||
|
ga=b.endSymbol(),Pc="{{"==Na||"}}"==ga?oa:function(a){return a.replace(/\{\{/g,Na).replace(/}}/g,ga)},za=/^ngAttr[A-Z]/;B.$$addBindingInfo=l?function(a,b){var c=a.data("$binding")||[];D(b)?c=c.concat(b):c.push(b);a.data("$binding",c)}:x;B.$$addBindingClass=l?function(a){M(a,"ng-binding")}:x;B.$$addScopeInfo=l?function(a,b,c,d){a.data(c?d?"$isolateScopeNoTemplate":"$isolateScope":"$scope",b)}:x;B.$$addScopeClass=l?function(a,b){M(a,b?"ng-isolate-scope":"ng-scope")}:x;return B}]}function wa(b){return bb(b.replace(nf,
|
||||||
|
""))}function Rc(b,a){var c="",d=b.split(/\s+/),e=a.split(/\s+/),f=0;a:for(;f<d.length;f++){for(var g=d[f],h=0;h<e.length;h++)if(g==e[h])continue a;c+=(0<c.length?" ":"")+g}return c}function Qc(b){b=A(b);var a=b.length;if(1>=a)return b;for(;a--;)8===b[a].nodeType&&of.call(b,a,1);return b}function Ce(){var b={},a=!1,c=/^(\S+)(\s+as\s+(\w+))?$/;this.register=function(a,c){La(a,"controller");K(a)?C(b,a):b[a]=c};this.allowGlobals=function(){a=!0};this.$get=["$injector","$window",function(d,e){function f(a,
|
||||||
|
b,c,d){if(!a||!K(a.$scope))throw z("$controller")("noscp",d,b);a.$scope[b]=c}return function(g,h,k,l){var m,p,s;k=!0===k;l&&I(l)&&(s=l);I(g)&&(l=g.match(c),p=l[1],s=s||l[3],g=b.hasOwnProperty(p)?b[p]:tc(h.$scope,p,!0)||(a?tc(e,p,!0):u),pb(g,p,!0));if(k)return k=(D(g)?g[g.length-1]:g).prototype,m=Object.create(k),s&&f(h,s,m,p||g.name),C(function(){d.invoke(g,m,h,p);return m},{instance:m,identifier:s});m=d.instantiate(g,h,p);s&&f(h,s,m,p||g.name);return m}}]}function De(){this.$get=["$window",function(b){return A(b.document)}]}
|
||||||
|
function Ee(){this.$get=["$log",function(b){return function(a,c){b.error.apply(b,arguments)}}]}function Yb(b,a){if(I(b)){b=b.replace(pf,"");var c=a("Content-Type");if(c&&0===c.indexOf(Sc)&&b.trim()||qf.test(b)&&rf.test(b))b=oc(b)}return b}function Tc(b){var a=ia(),c,d,e;if(!b)return a;r(b.split("\n"),function(b){e=b.indexOf(":");c=R(P(b.substr(0,e)));d=P(b.substr(e+1));c&&(a[c]=a[c]?a[c]+", "+d:d)});return a}function Uc(b){var a=K(b)?b:u;return function(c){a||(a=Tc(b));return c?(c=a[R(c)],void 0===
|
||||||
|
c&&(c=null),c):a}}function Vc(b,a,c){if(F(c))return c(b,a);r(c,function(c){b=c(b,a)});return b}function He(){var b=this.defaults={transformResponse:[Yb],transformRequest:[function(a){return K(a)&&"[object File]"!==Ja.call(a)&&"[object Blob]"!==Ja.call(a)?Za(a):a}],headers:{common:{Accept:"application/json, text/plain, */*"},post:ua(Zb),put:ua(Zb),patch:ua(Zb)},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN"},a=!1;this.useApplyAsync=function(b){return y(b)?(a=!!b,this):a};var c=this.interceptors=
|
||||||
|
[];this.$get=["$httpBackend","$browser","$cacheFactory","$rootScope","$q","$injector",function(d,e,f,g,h,k){function l(a){function c(a){var b=C({},a);b.data=a.data?Vc(a.data,a.headers,d.transformResponse):a.data;a=a.status;return 200<=a&&300>a?b:h.reject(b)}var d={method:"get",transformRequest:b.transformRequest,transformResponse:b.transformResponse},e=function(a){var c=b.headers,d=C({},a.headers),e,f,c=C({},c.common,c[R(a.method)]);a:for(e in c){a=R(e);for(f in d)if(R(f)===a)continue a;d[e]=c[e]}(function(a){var b;
|
||||||
|
r(a,function(c,d){F(c)&&(b=c(),null!=b?a[d]=b:delete a[d])})})(d);return d}(a);if(!ha.isObject(a))throw z("$http")("badreq",a);C(d,a);d.headers=e;d.method=rb(d.method);var f=[function(a){e=a.headers;var d=Vc(a.data,Uc(e),a.transformRequest);G(d)&&r(e,function(a,b){"content-type"===R(b)&&delete e[b]});G(a.withCredentials)&&!G(b.withCredentials)&&(a.withCredentials=b.withCredentials);return m(a,d,e).then(c,c)},u],g=h.when(d);for(r(t,function(a){(a.request||a.requestError)&&f.unshift(a.request,a.requestError);
|
||||||
|
(a.response||a.responseError)&&f.push(a.response,a.responseError)});f.length;){a=f.shift();var k=f.shift(),g=g.then(a,k)}g.success=function(a){g.then(function(b){a(b.data,b.status,b.headers,d)});return g};g.error=function(a){g.then(null,function(b){a(b.data,b.status,b.headers,d)});return g};return g}function m(c,f,k){function m(b,c,d,e){function f(){w(c,b,d,e)}M&&(200<=b&&300>b?M.put(r,[b,c,Tc(d),e]):M.remove(r));a?g.$applyAsync(f):(f(),g.$$phase||g.$apply())}function w(a,b,d,e){b=Math.max(b,0);(200<=
|
||||||
|
b&&300>b?E.resolve:E.reject)({data:a,status:b,headers:Uc(d),config:c,statusText:e})}function t(){var a=l.pendingRequests.indexOf(c);-1!==a&&l.pendingRequests.splice(a,1)}var E=h.defer(),H=E.promise,M,B,r=p(c.url,c.params);l.pendingRequests.push(c);H.then(t,t);!c.cache&&!b.cache||!1===c.cache||"GET"!==c.method&&"JSONP"!==c.method||(M=K(c.cache)?c.cache:K(b.cache)?b.cache:s);if(M)if(B=M.get(r),y(B)){if(B&&F(B.then))return B.then(t,t),B;D(B)?w(B[1],B[0],ua(B[2]),B[3]):w(B,200,{},"OK")}else M.put(r,H);
|
||||||
|
G(B)&&((B=Wc(c.url)?e.cookies()[c.xsrfCookieName||b.xsrfCookieName]:u)&&(k[c.xsrfHeaderName||b.xsrfHeaderName]=B),d(c.method,r,f,m,k,c.timeout,c.withCredentials,c.responseType));return H}function p(a,b){if(!b)return a;var c=[];Bd(b,function(a,b){null===a||G(a)||(D(a)||(a=[a]),r(a,function(a){K(a)&&(a=fa(a)?a.toISOString():Za(a));c.push(Da(b)+"="+Da(a))}))});0<c.length&&(a+=(-1==a.indexOf("?")?"?":"&")+c.join("&"));return a}var s=f("$http"),t=[];r(c,function(a){t.unshift(I(a)?k.get(a):k.invoke(a))});
|
||||||
|
l.pendingRequests=[];(function(a){r(arguments,function(a){l[a]=function(b,c){return l(C(c||{},{method:a,url:b}))}})})("get","delete","head","jsonp");(function(a){r(arguments,function(a){l[a]=function(b,c,d){return l(C(d||{},{method:a,url:b,data:c}))}})})("post","put","patch");l.defaults=b;return l}]}function sf(){return new U.XMLHttpRequest}function Ie(){this.$get=["$browser","$window","$document",function(b,a,c){return tf(b,sf,b.defer,a.angular.callbacks,c[0])}]}function tf(b,a,c,d,e){function f(a,
|
||||||
|
b,c){var f=e.createElement("script"),m=null;f.type="text/javascript";f.src=a;f.async=!0;m=function(a){f.removeEventListener("load",m,!1);f.removeEventListener("error",m,!1);e.body.removeChild(f);f=null;var g=-1,t="unknown";a&&("load"!==a.type||d[b].called||(a={type:"error"}),t=a.type,g="error"===a.type?404:200);c&&c(g,t)};f.addEventListener("load",m,!1);f.addEventListener("error",m,!1);e.body.appendChild(f);return m}return function(e,h,k,l,m,p,s,t){function q(){v&&v();w&&w.abort()}function N(a,d,
|
||||||
|
e,f,g){E&&c.cancel(E);v=w=null;a(d,e,f,g);b.$$completeOutstandingRequest(x)}b.$$incOutstandingRequestCount();h=h||b.url();if("jsonp"==R(e)){var n="_"+(d.counter++).toString(36);d[n]=function(a){d[n].data=a;d[n].called=!0};var v=f(h.replace("JSON_CALLBACK","angular.callbacks."+n),n,function(a,b){N(l,a,d[n].data,"",b);d[n]=x})}else{var w=a();w.open(e,h,!0);r(m,function(a,b){y(a)&&w.setRequestHeader(b,a)});w.onload=function(){var a=w.statusText||"",b="response"in w?w.response:w.responseText,c=1223===
|
||||||
|
w.status?204:w.status;0===c&&(c=b?200:"file"==Aa(h).protocol?404:0);N(l,c,b,w.getAllResponseHeaders(),a)};e=function(){N(l,-1,null,null,"")};w.onerror=e;w.onabort=e;s&&(w.withCredentials=!0);if(t)try{w.responseType=t}catch(O){if("json"!==t)throw O;}w.send(k||null)}if(0<p)var E=c(q,p);else p&&F(p.then)&&p.then(q)}}function Fe(){var b="{{",a="}}";this.startSymbol=function(a){return a?(b=a,this):b};this.endSymbol=function(b){return b?(a=b,this):a};this.$get=["$parse","$exceptionHandler","$sce",function(c,
|
||||||
|
d,e){function f(a){return"\\\\\\"+a}function g(f,g,t,q){function N(c){return c.replace(l,b).replace(m,a)}function n(a){try{var b=a;a=t?e.getTrusted(t,b):e.valueOf(b);var c;if(q&&!y(a))c=a;else if(null==a)c="";else{switch(typeof a){case "string":break;case "number":a=""+a;break;default:a=Za(a)}c=a}return c}catch(g){c=$b("interr",f,g.toString()),d(c)}}q=!!q;for(var v,w,O=0,E=[],H=[],M=f.length,B=[],r=[];O<M;)if(-1!=(v=f.indexOf(b,O))&&-1!=(w=f.indexOf(a,v+h)))O!==v&&B.push(N(f.substring(O,v))),O=f.substring(v+
|
||||||
|
h,w),E.push(O),H.push(c(O,n)),O=w+k,r.push(B.length),B.push("");else{O!==M&&B.push(N(f.substring(O)));break}if(t&&1<B.length)throw $b("noconcat",f);if(!g||E.length){var L=function(a){for(var b=0,c=E.length;b<c;b++){if(q&&G(a[b]))return;B[r[b]]=a[b]}return B.join("")};return C(function(a){var b=0,c=E.length,e=Array(c);try{for(;b<c;b++)e[b]=H[b](a);return L(e)}catch(g){a=$b("interr",f,g.toString()),d(a)}},{exp:f,expressions:E,$$watchDelegate:function(a,b,c){var d;return a.$watchGroup(H,function(c,e){var f=
|
||||||
|
L(c);F(b)&&b.call(this,f,c!==e?d:f,a);d=f},c)}})}}var h=b.length,k=a.length,l=new RegExp(b.replace(/./g,f),"g"),m=new RegExp(a.replace(/./g,f),"g");g.startSymbol=function(){return b};g.endSymbol=function(){return a};return g}]}function Ge(){this.$get=["$rootScope","$window","$q","$$q",function(b,a,c,d){function e(e,h,k,l){var m=a.setInterval,p=a.clearInterval,s=0,t=y(l)&&!l,q=(t?d:c).defer(),N=q.promise;k=y(k)?k:0;N.then(null,null,e);N.$$intervalId=m(function(){q.notify(s++);0<k&&s>=k&&(q.resolve(s),
|
||||||
|
p(N.$$intervalId),delete f[N.$$intervalId]);t||b.$apply()},h);f[N.$$intervalId]=q;return N}var f={};e.cancel=function(b){return b&&b.$$intervalId in f?(f[b.$$intervalId].reject("canceled"),a.clearInterval(b.$$intervalId),delete f[b.$$intervalId],!0):!1};return e}]}function Od(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4",
|
||||||
|
posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},DATETIME_FORMATS:{MONTH:"January February March April May June July August September October November December".split(" "),SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",
|
||||||
|
mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",shortTime:"h:mm a"},pluralCat:function(b){return 1===b?"one":"other"}}}}function ac(b){b=b.split("/");for(var a=b.length;a--;)b[a]=nb(b[a]);return b.join("/")}function Xc(b,a){var c=Aa(b);a.$$protocol=c.protocol;a.$$host=c.hostname;a.$$port=$(c.port)||uf[c.protocol]||null}function Yc(b,a){var c="/"!==b.charAt(0);c&&(b="/"+b);var d=Aa(b);a.$$path=decodeURIComponent(c&&"/"===d.pathname.charAt(0)?d.pathname.substring(1):d.pathname);a.$$search=
|
||||||
|
qc(d.search);a.$$hash=decodeURIComponent(d.hash);a.$$path&&"/"!=a.$$path.charAt(0)&&(a.$$path="/"+a.$$path)}function xa(b,a){if(0===a.indexOf(b))return a.substr(b.length)}function Fa(b){var a=b.indexOf("#");return-1==a?b:b.substr(0,a)}function bc(b){return b.substr(0,Fa(b).lastIndexOf("/")+1)}function cc(b,a){this.$$html5=!0;a=a||"";var c=bc(b);Xc(b,this);this.$$parse=function(a){var b=xa(c,a);if(!I(b))throw eb("ipthprfx",a,c);Yc(b,this);this.$$path||(this.$$path="/");this.$$compose()};this.$$compose=
|
||||||
|
function(){var a=Kb(this.$$search),b=this.$$hash?"#"+nb(this.$$hash):"";this.$$url=ac(this.$$path)+(a?"?"+a:"")+b;this.$$absUrl=c+this.$$url.substr(1)};this.$$parseLinkUrl=function(d,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;(f=xa(b,d))!==u?(g=f,g=(f=xa(a,f))!==u?c+(xa("/",f)||f):b+g):(f=xa(c,d))!==u?g=c+f:c==d+"/"&&(g=c);g&&this.$$parse(g);return!!g}}function dc(b,a){var c=bc(b);Xc(b,this);this.$$parse=function(d){var e=xa(b,d)||xa(c,d),e="#"==e.charAt(0)?xa(a,e):this.$$html5?e:
|
||||||
|
"";if(!I(e))throw eb("ihshprfx",d,a);Yc(e,this);d=this.$$path;var f=/^\/[A-Z]:(\/.*)/;0===e.indexOf(b)&&(e=e.replace(b,""));f.exec(e)||(d=(e=f.exec(d))?e[1]:d);this.$$path=d;this.$$compose()};this.$$compose=function(){var c=Kb(this.$$search),e=this.$$hash?"#"+nb(this.$$hash):"";this.$$url=ac(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=b+(this.$$url?a+this.$$url:"")};this.$$parseLinkUrl=function(a,c){return Fa(b)==Fa(a)?(this.$$parse(a),!0):!1}}function Zc(b,a){this.$$html5=!0;dc.apply(this,arguments);
|
||||||
|
var c=bc(b);this.$$parseLinkUrl=function(d,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;b==Fa(d)?f=d:(g=xa(c,d))?f=b+a+g:c===d+"/"&&(f=c);f&&this.$$parse(f);return!!f};this.$$compose=function(){var c=Kb(this.$$search),e=this.$$hash?"#"+nb(this.$$hash):"";this.$$url=ac(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=b+a+this.$$url}}function Bb(b){return function(){return this[b]}}function $c(b,a){return function(c){if(G(c))return this[b];this[b]=a(c);this.$$compose();return this}}function Je(){var b=
|
||||||
|
"",a={enabled:!1,requireBase:!0,rewriteLinks:!0};this.hashPrefix=function(a){return y(a)?(b=a,this):b};this.html5Mode=function(b){return Ua(b)?(a.enabled=b,this):K(b)?(Ua(b.enabled)&&(a.enabled=b.enabled),Ua(b.requireBase)&&(a.requireBase=b.requireBase),Ua(b.rewriteLinks)&&(a.rewriteLinks=b.rewriteLinks),this):a};this.$get=["$rootScope","$browser","$sniffer","$rootElement",function(c,d,e,f){function g(a,b,c){var e=k.url(),f=k.$$state;try{d.url(a,b,c),k.$$state=d.state()}catch(g){throw k.url(e),k.$$state=
|
||||||
|
f,g;}}function h(a,b){c.$broadcast("$locationChangeSuccess",k.absUrl(),a,k.$$state,b)}var k,l;l=d.baseHref();var m=d.url(),p;if(a.enabled){if(!l&&a.requireBase)throw eb("nobase");p=m.substring(0,m.indexOf("/",m.indexOf("//")+2))+(l||"/");l=e.history?cc:Zc}else p=Fa(m),l=dc;k=new l(p,"#"+b);k.$$parseLinkUrl(m,m);k.$$state=d.state();var s=/^\s*(javascript|mailto):/i;f.on("click",function(b){if(a.rewriteLinks&&!b.ctrlKey&&!b.metaKey&&2!=b.which){for(var e=A(b.target);"a"!==ta(e[0]);)if(e[0]===f[0]||
|
||||||
|
!(e=e.parent())[0])return;var g=e.prop("href"),h=e.attr("href")||e.attr("xlink:href");K(g)&&"[object SVGAnimatedString]"===g.toString()&&(g=Aa(g.animVal).href);s.test(g)||!g||e.attr("target")||b.isDefaultPrevented()||!k.$$parseLinkUrl(g,h)||(b.preventDefault(),k.absUrl()!=d.url()&&(c.$apply(),U.angular["ff-684208-preventDefault"]=!0))}});k.absUrl()!=m&&d.url(k.absUrl(),!0);var t=!0;d.onUrlChange(function(a,b){c.$evalAsync(function(){var d=k.absUrl(),e=k.$$state,f;k.$$parse(a);k.$$state=b;f=c.$broadcast("$locationChangeStart",
|
||||||
|
a,d,b,e).defaultPrevented;k.absUrl()===a&&(f?(k.$$parse(d),k.$$state=e,g(d,!1,e)):(t=!1,h(d,e)))});c.$$phase||c.$digest()});c.$watch(function(){var a=d.url(),b=d.state(),f=k.$$replace,l=a!==k.absUrl()||k.$$html5&&e.history&&b!==k.$$state;if(t||l)t=!1,c.$evalAsync(function(){var d=k.absUrl(),e=c.$broadcast("$locationChangeStart",d,a,k.$$state,b).defaultPrevented;k.absUrl()===d&&(e?(k.$$parse(a),k.$$state=b):(l&&g(d,f,b===k.$$state?null:k.$$state),h(a,b)))});k.$$replace=!1});return k}]}function Ke(){var b=
|
||||||
|
!0,a=this;this.debugEnabled=function(a){return y(a)?(b=a,this):b};this.$get=["$window",function(c){function d(a){a instanceof Error&&(a.stack?a=a.message&&-1===a.stack.indexOf(a.message)?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function e(a){var b=c.console||{},e=b[a]||b.log||x;a=!1;try{a=!!e.apply}catch(k){}return a?function(){var a=[];r(arguments,function(b){a.push(d(b))});return e.apply(b,a)}:function(a,b){e(a,null==b?"":b)}}return{log:e("log"),
|
||||||
|
info:e("info"),warn:e("warn"),error:e("error"),debug:function(){var c=e("debug");return function(){b&&c.apply(a,arguments)}}()}}]}function ra(b,a){if("__defineGetter__"===b||"__defineSetter__"===b||"__lookupGetter__"===b||"__lookupSetter__"===b||"__proto__"===b)throw la("isecfld",a);return b}function sa(b,a){if(b){if(b.constructor===b)throw la("isecfn",a);if(b.window===b)throw la("isecwindow",a);if(b.children&&(b.nodeName||b.prop&&b.attr&&b.find))throw la("isecdom",a);if(b===Object)throw la("isecobj",
|
||||||
|
a);}return b}function ec(b){return b.constant}function Oa(b,a,c,d){sa(b,d);a=a.split(".");for(var e,f=0;1<a.length;f++){e=ra(a.shift(),d);var g=sa(b[e],d);g||(g={},b[e]=g);b=g}e=ra(a.shift(),d);sa(b[e],d);return b[e]=c}function Pa(b){return"constructor"==b}function ad(b,a,c,d,e,f,g){ra(b,f);ra(a,f);ra(c,f);ra(d,f);ra(e,f);var h=function(a){return sa(a,f)},k=g||Pa(b)?h:oa,l=g||Pa(a)?h:oa,m=g||Pa(c)?h:oa,p=g||Pa(d)?h:oa,s=g||Pa(e)?h:oa;return function(f,g){var h=g&&g.hasOwnProperty(b)?g:f;if(null==
|
||||||
|
h)return h;h=k(h[b]);if(!a)return h;if(null==h)return u;h=l(h[a]);if(!c)return h;if(null==h)return u;h=m(h[c]);if(!d)return h;if(null==h)return u;h=p(h[d]);return e?null==h?u:h=s(h[e]):h}}function vf(b,a){return function(c,d){return b(c,d,sa,a)}}function bd(b,a,c){var d=a.expensiveChecks,e=d?wf:xf,f=e[b];if(f)return f;var g=b.split("."),h=g.length;if(a.csp)f=6>h?ad(g[0],g[1],g[2],g[3],g[4],c,d):function(a,b){var e=0,f;do f=ad(g[e++],g[e++],g[e++],g[e++],g[e++],c,d)(a,b),b=u,a=f;while(e<h);return f};
|
||||||
|
else{var k="";d&&(k+="s = eso(s, fe);\nl = eso(l, fe);\n");var l=d;r(g,function(a,b){ra(a,c);var e=(b?"s":'((l&&l.hasOwnProperty("'+a+'"))?l:s)')+"."+a;if(d||Pa(a))e="eso("+e+", fe)",l=!0;k+="if(s == null) return undefined;\ns="+e+";\n"});k+="return s;";a=new Function("s","l","eso","fe",k);a.toString=ca(k);l&&(a=vf(a,c));f=a}f.sharedGetter=!0;f.assign=function(a,c){return Oa(a,b,c,b)};return e[b]=f}function fc(b){return F(b.valueOf)?b.valueOf():yf.call(b)}function Le(){var b=ia(),a=ia();this.$get=
|
||||||
|
["$filter","$sniffer",function(c,d){function e(a){var b=a;a.sharedGetter&&(b=function(b,c){return a(b,c)},b.literal=a.literal,b.constant=a.constant,b.assign=a.assign);return b}function f(a,b){for(var c=0,d=a.length;c<d;c++){var e=a[c];e.constant||(e.inputs?f(e.inputs,b):-1===b.indexOf(e)&&b.push(e))}return b}function g(a,b){return null==a||null==b?a===b:"object"===typeof a&&(a=fc(a),"object"===typeof a)?!1:a===b||a!==a&&b!==b}function h(a,b,c,d){var e=d.$$inputs||(d.$$inputs=f(d.inputs,[])),h;if(1===
|
||||||
|
e.length){var k=g,e=e[0];return a.$watch(function(a){var b=e(a);g(b,k)||(h=d(a),k=b&&fc(b));return h},b,c)}for(var l=[],s=0,m=e.length;s<m;s++)l[s]=g;return a.$watch(function(a){for(var b=!1,c=0,f=e.length;c<f;c++){var k=e[c](a);if(b||(b=!g(k,l[c])))l[c]=k&&fc(k)}b&&(h=d(a));return h},b,c)}function k(a,b,c,d){var e,f;return e=a.$watch(function(a){return d(a)},function(a,c,d){f=a;F(b)&&b.apply(this,arguments);y(a)&&d.$$postDigest(function(){y(f)&&e()})},c)}function l(a,b,c,d){function e(a){var b=!0;
|
||||||
|
r(a,function(a){y(a)||(b=!1)});return b}var f,g;return f=a.$watch(function(a){return d(a)},function(a,c,d){g=a;F(b)&&b.call(this,a,c,d);e(a)&&d.$$postDigest(function(){e(g)&&f()})},c)}function m(a,b,c,d){var e;return e=a.$watch(function(a){return d(a)},function(a,c,d){F(b)&&b.apply(this,arguments);e()},c)}function p(a,b){if(!b)return a;var c=a.$$watchDelegate,c=c!==l&&c!==k?function(c,d){var e=a(c,d);return b(e,c,d)}:function(c,d){var e=a(c,d),f=b(e,c,d);return y(e)?f:e};a.$$watchDelegate&&a.$$watchDelegate!==
|
||||||
|
h?c.$$watchDelegate=a.$$watchDelegate:b.$stateful||(c.$$watchDelegate=h,c.inputs=[a]);return c}var s={csp:d.csp,expensiveChecks:!1},t={csp:d.csp,expensiveChecks:!0};return function(d,f,g){var v,w,O;switch(typeof d){case "string":O=d=d.trim();var E=g?a:b;v=E[O];v||(":"===d.charAt(0)&&":"===d.charAt(1)&&(w=!0,d=d.substring(2)),g=g?t:s,v=new gc(g),v=(new fb(v,c,g)).parse(d),v.constant?v.$$watchDelegate=m:w?(v=e(v),v.$$watchDelegate=v.literal?l:k):v.inputs&&(v.$$watchDelegate=h),E[O]=v);return p(v,f);
|
||||||
|
case "function":return p(d,f);default:return p(x,f)}}}]}function Ne(){this.$get=["$rootScope","$exceptionHandler",function(b,a){return cd(function(a){b.$evalAsync(a)},a)}]}function Oe(){this.$get=["$browser","$exceptionHandler",function(b,a){return cd(function(a){b.defer(a)},a)}]}function cd(b,a){function c(a,b,c){function d(b){return function(c){e||(e=!0,b.call(a,c))}}var e=!1;return[d(b),d(c)]}function d(){this.$$state={status:0}}function e(a,b){return function(c){b.call(a,c)}}function f(c){!c.processScheduled&&
|
||||||
|
c.pending&&(c.processScheduled=!0,b(function(){var b,d,e;e=c.pending;c.processScheduled=!1;c.pending=u;for(var f=0,g=e.length;f<g;++f){d=e[f][0];b=e[f][c.status];try{F(b)?d.resolve(b(c.value)):1===c.status?d.resolve(c.value):d.reject(c.value)}catch(h){d.reject(h),a(h)}}}))}function g(){this.promise=new d;this.resolve=e(this,this.resolve);this.reject=e(this,this.reject);this.notify=e(this,this.notify)}var h=z("$q",TypeError);d.prototype={then:function(a,b,c){var d=new g;this.$$state.pending=this.$$state.pending||
|
||||||
|
[];this.$$state.pending.push([d,a,b,c]);0<this.$$state.status&&f(this.$$state);return d.promise},"catch":function(a){return this.then(null,a)},"finally":function(a,b){return this.then(function(b){return l(b,!0,a)},function(b){return l(b,!1,a)},b)}};g.prototype={resolve:function(a){this.promise.$$state.status||(a===this.promise?this.$$reject(h("qcycle",a)):this.$$resolve(a))},$$resolve:function(b){var d,e;e=c(this,this.$$resolve,this.$$reject);try{if(K(b)||F(b))d=b&&b.then;F(d)?(this.promise.$$state.status=
|
||||||
|
-1,d.call(b,e[0],e[1],this.notify)):(this.promise.$$state.value=b,this.promise.$$state.status=1,f(this.promise.$$state))}catch(g){e[1](g),a(g)}},reject:function(a){this.promise.$$state.status||this.$$reject(a)},$$reject:function(a){this.promise.$$state.value=a;this.promise.$$state.status=2;f(this.promise.$$state)},notify:function(c){var d=this.promise.$$state.pending;0>=this.promise.$$state.status&&d&&d.length&&b(function(){for(var b,e,f=0,g=d.length;f<g;f++){e=d[f][0];b=d[f][3];try{e.notify(F(b)?
|
||||||
|
b(c):c)}catch(h){a(h)}}})}};var k=function(a,b){var c=new g;b?c.resolve(a):c.reject(a);return c.promise},l=function(a,b,c){var d=null;try{F(c)&&(d=c())}catch(e){return k(e,!1)}return d&&F(d.then)?d.then(function(){return k(a,b)},function(a){return k(a,!1)}):k(a,b)},m=function(a,b,c,d){var e=new g;e.resolve(a);return e.promise.then(b,c,d)},p=function t(a){if(!F(a))throw h("norslvr",a);if(!(this instanceof t))return new t(a);var b=new g;a(function(a){b.resolve(a)},function(a){b.reject(a)});return b.promise};
|
||||||
|
p.defer=function(){return new g};p.reject=function(a){var b=new g;b.reject(a);return b.promise};p.when=m;p.all=function(a){var b=new g,c=0,d=D(a)?[]:{};r(a,function(a,e){c++;m(a).then(function(a){d.hasOwnProperty(e)||(d[e]=a,--c||b.resolve(d))},function(a){d.hasOwnProperty(e)||b.reject(a)})});0===c&&b.resolve(d);return b.promise};return p}function Xe(){this.$get=["$window","$timeout",function(b,a){var c=b.requestAnimationFrame||b.webkitRequestAnimationFrame||b.mozRequestAnimationFrame,d=b.cancelAnimationFrame||
|
||||||
|
b.webkitCancelAnimationFrame||b.mozCancelAnimationFrame||b.webkitCancelRequestAnimationFrame,e=!!c,f=e?function(a){var b=c(a);return function(){d(b)}}:function(b){var c=a(b,16.66,!1);return function(){a.cancel(c)}};f.supported=e;return f}]}function Me(){var b=10,a=z("$rootScope"),c=null,d=null;this.digestTtl=function(a){arguments.length&&(b=a);return b};this.$get=["$injector","$exceptionHandler","$parse","$browser",function(e,f,g,h){function k(){this.$id=++kb;this.$$phase=this.$parent=this.$$watchers=
|
||||||
|
this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null;this.$root=this;this.$$destroyed=!1;this.$$listeners={};this.$$listenerCount={};this.$$isolateBindings=null}function l(b){if(q.$$phase)throw a("inprog",q.$$phase);q.$$phase=b}function m(a,b,c){do a.$$listenerCount[c]-=b,0===a.$$listenerCount[c]&&delete a.$$listenerCount[c];while(a=a.$parent)}function p(){}function s(){for(;v.length;)try{v.shift()()}catch(a){f(a)}d=null}function t(){null===d&&(d=h.defer(function(){q.$apply(s)}))}
|
||||||
|
k.prototype={constructor:k,$new:function(a,b){function c(){d.$$destroyed=!0}var d;b=b||this;a?(d=new k,d.$root=this.$root):(this.$$ChildScope||(this.$$ChildScope=function(){this.$$watchers=this.$$nextSibling=this.$$childHead=this.$$childTail=null;this.$$listeners={};this.$$listenerCount={};this.$id=++kb;this.$$ChildScope=null},this.$$ChildScope.prototype=this),d=new this.$$ChildScope);d.$parent=b;d.$$prevSibling=b.$$childTail;b.$$childHead?(b.$$childTail.$$nextSibling=d,b.$$childTail=d):b.$$childHead=
|
||||||
|
b.$$childTail=d;(a||b!=this)&&d.$on("$destroy",c);return d},$watch:function(a,b,d){var e=g(a);if(e.$$watchDelegate)return e.$$watchDelegate(this,b,d,e);var f=this.$$watchers,h={fn:b,last:p,get:e,exp:a,eq:!!d};c=null;F(b)||(h.fn=x);f||(f=this.$$watchers=[]);f.unshift(h);return function(){Va(f,h);c=null}},$watchGroup:function(a,b){function c(){h=!1;k?(k=!1,b(e,e,g)):b(e,d,g)}var d=Array(a.length),e=Array(a.length),f=[],g=this,h=!1,k=!0;if(!a.length){var l=!0;g.$evalAsync(function(){l&&b(e,e,g)});return function(){l=
|
||||||
|
!1}}if(1===a.length)return this.$watch(a[0],function(a,c,f){e[0]=a;d[0]=c;b(e,a===c?e:d,f)});r(a,function(a,b){var k=g.$watch(a,function(a,f){e[b]=a;d[b]=f;h||(h=!0,g.$evalAsync(c))});f.push(k)});return function(){for(;f.length;)f.shift()()}},$watchCollection:function(a,b){function c(a){e=a;var b,d,g,h;if(!G(e)){if(K(e))if(Ra(e))for(f!==p&&(f=p,n=f.length=0,l++),a=e.length,n!==a&&(l++,f.length=n=a),b=0;b<a;b++)h=f[b],g=e[b],d=h!==h&&g!==g,d||h===g||(l++,f[b]=g);else{f!==s&&(f=s={},n=0,l++);a=0;for(b in e)e.hasOwnProperty(b)&&
|
||||||
|
(a++,g=e[b],h=f[b],b in f?(d=h!==h&&g!==g,d||h===g||(l++,f[b]=g)):(n++,f[b]=g,l++));if(n>a)for(b in l++,f)e.hasOwnProperty(b)||(n--,delete f[b])}else f!==e&&(f=e,l++);return l}}c.$stateful=!0;var d=this,e,f,h,k=1<b.length,l=0,m=g(a,c),p=[],s={},q=!0,n=0;return this.$watch(m,function(){q?(q=!1,b(e,e,d)):b(e,h,d);if(k)if(K(e))if(Ra(e)){h=Array(e.length);for(var a=0;a<e.length;a++)h[a]=e[a]}else for(a in h={},e)Jb.call(e,a)&&(h[a]=e[a]);else h=e})},$digest:function(){var e,g,k,m,t,v,r=b,L,u=[],y,Q;l("$digest");
|
||||||
|
h.$$checkUrlChange();this===q&&null!==d&&(h.defer.cancel(d),s());c=null;do{v=!1;for(L=this;N.length;){try{Q=N.shift(),Q.scope.$eval(Q.expression)}catch(z){f(z)}c=null}a:do{if(m=L.$$watchers)for(t=m.length;t--;)try{if(e=m[t])if((g=e.get(L))!==(k=e.last)&&!(e.eq?pa(g,k):"number"===typeof g&&"number"===typeof k&&isNaN(g)&&isNaN(k)))v=!0,c=e,e.last=e.eq?Ca(g,null):g,e.fn(g,k===p?g:k,L),5>r&&(y=4-r,u[y]||(u[y]=[]),u[y].push({msg:F(e.exp)?"fn: "+(e.exp.name||e.exp.toString()):e.exp,newVal:g,oldVal:k}));
|
||||||
|
else if(e===c){v=!1;break a}}catch(A){f(A)}if(!(m=L.$$childHead||L!==this&&L.$$nextSibling))for(;L!==this&&!(m=L.$$nextSibling);)L=L.$parent}while(L=m);if((v||N.length)&&!r--)throw q.$$phase=null,a("infdig",b,u);}while(v||N.length);for(q.$$phase=null;n.length;)try{n.shift()()}catch(da){f(da)}},$destroy:function(){if(!this.$$destroyed){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;if(this!==q){for(var b in this.$$listenerCount)m(this,this.$$listenerCount[b],b);a.$$childHead==this&&
|
||||||
|
(a.$$childHead=this.$$nextSibling);a.$$childTail==this&&(a.$$childTail=this.$$prevSibling);this.$$prevSibling&&(this.$$prevSibling.$$nextSibling=this.$$nextSibling);this.$$nextSibling&&(this.$$nextSibling.$$prevSibling=this.$$prevSibling);this.$destroy=this.$digest=this.$apply=this.$evalAsync=this.$applyAsync=x;this.$on=this.$watch=this.$watchGroup=function(){return x};this.$$listeners={};this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=this.$root=this.$$watchers=
|
||||||
|
null}}},$eval:function(a,b){return g(a)(this,b)},$evalAsync:function(a){q.$$phase||N.length||h.defer(function(){N.length&&q.$digest()});N.push({scope:this,expression:a})},$$postDigest:function(a){n.push(a)},$apply:function(a){try{return l("$apply"),this.$eval(a)}catch(b){f(b)}finally{q.$$phase=null;try{q.$digest()}catch(c){throw f(c),c;}}},$applyAsync:function(a){function b(){c.$eval(a)}var c=this;a&&v.push(b);t()},$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=c=[]);c.push(b);
|
||||||
|
var d=this;do d.$$listenerCount[a]||(d.$$listenerCount[a]=0),d.$$listenerCount[a]++;while(d=d.$parent);var e=this;return function(){var d=c.indexOf(b);-1!==d&&(c[d]=null,m(e,1,a))}},$emit:function(a,b){var c=[],d,e=this,g=!1,h={name:a,targetScope:e,stopPropagation:function(){g=!0},preventDefault:function(){h.defaultPrevented=!0},defaultPrevented:!1},k=Xa([h],arguments,1),l,m;do{d=e.$$listeners[a]||c;h.currentScope=e;l=0;for(m=d.length;l<m;l++)if(d[l])try{d[l].apply(null,k)}catch(p){f(p)}else d.splice(l,
|
||||||
|
1),l--,m--;if(g)return h.currentScope=null,h;e=e.$parent}while(e);h.currentScope=null;return h},$broadcast:function(a,b){var c=this,d=this,e={name:a,targetScope:this,preventDefault:function(){e.defaultPrevented=!0},defaultPrevented:!1};if(!this.$$listenerCount[a])return e;for(var g=Xa([e],arguments,1),h,k;c=d;){e.currentScope=c;d=c.$$listeners[a]||[];h=0;for(k=d.length;h<k;h++)if(d[h])try{d[h].apply(null,g)}catch(l){f(l)}else d.splice(h,1),h--,k--;if(!(d=c.$$listenerCount[a]&&c.$$childHead||c!==this&&
|
||||||
|
c.$$nextSibling))for(;c!==this&&!(d=c.$$nextSibling);)c=c.$parent}e.currentScope=null;return e}};var q=new k,N=q.$$asyncQueue=[],n=q.$$postDigestQueue=[],v=q.$$applyAsyncQueue=[];return q}]}function Pd(){var b=/^\s*(https?|ftp|mailto|tel|file):/,a=/^\s*((https?|ftp|file|blob):|data:image\/)/;this.aHrefSanitizationWhitelist=function(a){return y(a)?(b=a,this):b};this.imgSrcSanitizationWhitelist=function(b){return y(b)?(a=b,this):a};this.$get=function(){return function(c,d){var e=d?a:b,f;f=Aa(c).href;
|
||||||
|
return""===f||f.match(e)?c:"unsafe:"+f}}}function zf(b){if("self"===b)return b;if(I(b)){if(-1<b.indexOf("***"))throw Ba("iwcard",b);b=dd(b).replace("\\*\\*",".*").replace("\\*","[^:/.?&;]*");return new RegExp("^"+b+"$")}if(lb(b))return new RegExp("^"+b.source+"$");throw Ba("imatcher");}function ed(b){var a=[];y(b)&&r(b,function(b){a.push(zf(b))});return a}function Qe(){this.SCE_CONTEXTS=ma;var b=["self"],a=[];this.resourceUrlWhitelist=function(a){arguments.length&&(b=ed(a));return b};this.resourceUrlBlacklist=
|
||||||
|
function(b){arguments.length&&(a=ed(b));return a};this.$get=["$injector",function(c){function d(a,b){return"self"===a?Wc(b):!!a.exec(b.href)}function e(a){var b=function(a){this.$$unwrapTrustedValue=function(){return a}};a&&(b.prototype=new a);b.prototype.valueOf=function(){return this.$$unwrapTrustedValue()};b.prototype.toString=function(){return this.$$unwrapTrustedValue().toString()};return b}var f=function(a){throw Ba("unsafe");};c.has("$sanitize")&&(f=c.get("$sanitize"));var g=e(),h={};h[ma.HTML]=
|
||||||
|
e(g);h[ma.CSS]=e(g);h[ma.URL]=e(g);h[ma.JS]=e(g);h[ma.RESOURCE_URL]=e(h[ma.URL]);return{trustAs:function(a,b){var c=h.hasOwnProperty(a)?h[a]:null;if(!c)throw Ba("icontext",a,b);if(null===b||b===u||""===b)return b;if("string"!==typeof b)throw Ba("itype",a);return new c(b)},getTrusted:function(c,e){if(null===e||e===u||""===e)return e;var g=h.hasOwnProperty(c)?h[c]:null;if(g&&e instanceof g)return e.$$unwrapTrustedValue();if(c===ma.RESOURCE_URL){var g=Aa(e.toString()),p,s,t=!1;p=0;for(s=b.length;p<s;p++)if(d(b[p],
|
||||||
|
g)){t=!0;break}if(t)for(p=0,s=a.length;p<s;p++)if(d(a[p],g)){t=!1;break}if(t)return e;throw Ba("insecurl",e.toString());}if(c===ma.HTML)return f(e);throw Ba("unsafe");},valueOf:function(a){return a instanceof g?a.$$unwrapTrustedValue():a}}}]}function Pe(){var b=!0;this.enabled=function(a){arguments.length&&(b=!!a);return b};this.$get=["$parse","$sceDelegate",function(a,c){if(b&&8>Ha)throw Ba("iequirks");var d=ua(ma);d.isEnabled=function(){return b};d.trustAs=c.trustAs;d.getTrusted=c.getTrusted;d.valueOf=
|
||||||
|
c.valueOf;b||(d.trustAs=d.getTrusted=function(a,b){return b},d.valueOf=oa);d.parseAs=function(b,c){var e=a(c);return e.literal&&e.constant?e:a(c,function(a){return d.getTrusted(b,a)})};var e=d.parseAs,f=d.getTrusted,g=d.trustAs;r(ma,function(a,b){var c=R(b);d[bb("parse_as_"+c)]=function(b){return e(a,b)};d[bb("get_trusted_"+c)]=function(b){return f(a,b)};d[bb("trust_as_"+c)]=function(b){return g(a,b)}});return d}]}function Re(){this.$get=["$window","$document",function(b,a){var c={},d=$((/android (\d+)/.exec(R((b.navigator||
|
||||||
|
{}).userAgent))||[])[1]),e=/Boxee/i.test((b.navigator||{}).userAgent),f=a[0]||{},g,h=/^(Moz|webkit|ms)(?=[A-Z])/,k=f.body&&f.body.style,l=!1,m=!1;if(k){for(var p in k)if(l=h.exec(p)){g=l[0];g=g.substr(0,1).toUpperCase()+g.substr(1);break}g||(g="WebkitOpacity"in k&&"webkit");l=!!("transition"in k||g+"Transition"in k);m=!!("animation"in k||g+"Animation"in k);!d||l&&m||(l=I(f.body.style.webkitTransition),m=I(f.body.style.webkitAnimation))}return{history:!(!b.history||!b.history.pushState||4>d||e),hasEvent:function(a){if("input"==
|
||||||
|
a&&9==Ha)return!1;if(G(c[a])){var b=f.createElement("div");c[a]="on"+a in b}return c[a]},csp:$a(),vendorPrefix:g,transitions:l,animations:m,android:d}}]}function Te(){this.$get=["$templateCache","$http","$q",function(b,a,c){function d(e,f){d.totalPendingRequests++;var g=a.defaults&&a.defaults.transformResponse;if(D(g))for(var h=g,g=[],k=0;k<h.length;++k){var l=h[k];l!==Yb&&g.push(l)}else g===Yb&&(g=null);return a.get(e,{cache:b,transformResponse:g}).then(function(a){a=a.data;d.totalPendingRequests--;
|
||||||
|
b.put(e,a);return a},function(){d.totalPendingRequests--;if(!f)throw ka("tpload",e);return c.reject()})}d.totalPendingRequests=0;return d}]}function Ue(){this.$get=["$rootScope","$browser","$location",function(b,a,c){return{findBindings:function(a,b,c){a=a.getElementsByClassName("ng-binding");var g=[];r(a,function(a){var d=ha.element(a).data("$binding");d&&r(d,function(d){c?(new RegExp("(^|\\s)"+dd(b)+"(\\s|\\||$)")).test(d)&&g.push(a):-1!=d.indexOf(b)&&g.push(a)})});return g},findModels:function(a,
|
||||||
|
b,c){for(var g=["ng-","data-ng-","ng\\:"],h=0;h<g.length;++h){var k=a.querySelectorAll("["+g[h]+"model"+(c?"=":"*=")+'"'+b+'"]');if(k.length)return k}},getLocation:function(){return c.url()},setLocation:function(a){a!==c.url()&&(c.url(a),b.$digest())},whenStable:function(b){a.notifyWhenNoOutstandingRequests(b)}}}]}function Ve(){this.$get=["$rootScope","$browser","$q","$$q","$exceptionHandler",function(b,a,c,d,e){function f(f,k,l){var m=y(l)&&!l,p=(m?d:c).defer(),s=p.promise;k=a.defer(function(){try{p.resolve(f())}catch(a){p.reject(a),
|
||||||
|
e(a)}finally{delete g[s.$$timeoutId]}m||b.$apply()},k);s.$$timeoutId=k;g[k]=p;return s}var g={};f.cancel=function(b){return b&&b.$$timeoutId in g?(g[b.$$timeoutId].reject("canceled"),delete g[b.$$timeoutId],a.defer.cancel(b.$$timeoutId)):!1};return f}]}function Aa(b){Ha&&(Y.setAttribute("href",b),b=Y.href);Y.setAttribute("href",b);return{href:Y.href,protocol:Y.protocol?Y.protocol.replace(/:$/,""):"",host:Y.host,search:Y.search?Y.search.replace(/^\?/,""):"",hash:Y.hash?Y.hash.replace(/^#/,""):"",hostname:Y.hostname,
|
||||||
|
port:Y.port,pathname:"/"===Y.pathname.charAt(0)?Y.pathname:"/"+Y.pathname}}function Wc(b){b=I(b)?Aa(b):b;return b.protocol===fd.protocol&&b.host===fd.host}function We(){this.$get=ca(U)}function Bc(b){function a(c,d){if(K(c)){var e={};r(c,function(b,c){e[c]=a(c,b)});return e}return b.factory(c+"Filter",d)}this.register=a;this.$get=["$injector",function(a){return function(b){return a.get(b+"Filter")}}];a("currency",gd);a("date",hd);a("filter",Af);a("json",Bf);a("limitTo",Cf);a("lowercase",Df);a("number",
|
||||||
|
id);a("orderBy",jd);a("uppercase",Ef)}function Af(){return function(b,a,c){if(!D(b))return b;var d=typeof c,e=[];e.check=function(a,b){for(var c=0;c<e.length;c++)if(!e[c](a,b))return!1;return!0};"function"!==d&&(c="boolean"===d&&c?function(a,b){return ha.equals(a,b)}:function(a,b){if(a&&b&&"object"===typeof a&&"object"===typeof b){for(var d in a)if("$"!==d.charAt(0)&&Jb.call(a,d)&&c(a[d],b[d]))return!0;return!1}b=(""+b).toLowerCase();return-1<(""+a).toLowerCase().indexOf(b)});var f=function(a,b){if("string"===
|
||||||
|
typeof b&&"!"===b.charAt(0))return!f(a,b.substr(1));switch(typeof a){case "boolean":case "number":case "string":return c(a,b);case "object":switch(typeof b){case "object":return c(a,b);default:for(var d in a)if("$"!==d.charAt(0)&&f(a[d],b))return!0}return!1;case "array":for(d=0;d<a.length;d++)if(f(a[d],b))return!0;return!1;default:return!1}};switch(typeof a){case "boolean":case "number":case "string":a={$:a};case "object":for(var g in a)(function(b){"undefined"!==typeof a[b]&&e.push(function(c){return f("$"==
|
||||||
|
b?c:c&&c[b],a[b])})})(g);break;case "function":e.push(a);break;default:return b}d=[];for(g=0;g<b.length;g++){var h=b[g];e.check(h,g)&&d.push(h)}return d}}function gd(b){var a=b.NUMBER_FORMATS;return function(b,d,e){G(d)&&(d=a.CURRENCY_SYM);G(e)&&(e=a.PATTERNS[1].maxFrac);return null==b?b:kd(b,a.PATTERNS[1],a.GROUP_SEP,a.DECIMAL_SEP,e).replace(/\u00A4/g,d)}}function id(b){var a=b.NUMBER_FORMATS;return function(b,d){return null==b?b:kd(b,a.PATTERNS[0],a.GROUP_SEP,a.DECIMAL_SEP,d)}}function kd(b,a,c,
|
||||||
|
d,e){if(!isFinite(b)||K(b))return"";var f=0>b;b=Math.abs(b);var g=b+"",h="",k=[],l=!1;if(-1!==g.indexOf("e")){var m=g.match(/([\d\.]+)e(-?)(\d+)/);m&&"-"==m[2]&&m[3]>e+1?(g="0",b=0):(h=g,l=!0)}if(l)0<e&&-1<b&&1>b&&(h=b.toFixed(e));else{g=(g.split(ld)[1]||"").length;G(e)&&(e=Math.min(Math.max(a.minFrac,g),a.maxFrac));b=+(Math.round(+(b.toString()+"e"+e)).toString()+"e"+-e);0===b&&(f=!1);b=(""+b).split(ld);g=b[0];b=b[1]||"";var m=0,p=a.lgSize,s=a.gSize;if(g.length>=p+s)for(m=g.length-p,l=0;l<m;l++)0===
|
||||||
|
(m-l)%s&&0!==l&&(h+=c),h+=g.charAt(l);for(l=m;l<g.length;l++)0===(g.length-l)%p&&0!==l&&(h+=c),h+=g.charAt(l);for(;b.length<e;)b+="0";e&&"0"!==e&&(h+=d+b.substr(0,e))}k.push(f?a.negPre:a.posPre,h,f?a.negSuf:a.posSuf);return k.join("")}function Cb(b,a,c){var d="";0>b&&(d="-",b=-b);for(b=""+b;b.length<a;)b="0"+b;c&&(b=b.substr(b.length-a));return d+b}function Z(b,a,c,d){c=c||0;return function(e){e=e["get"+b]();if(0<c||e>-c)e+=c;0===e&&-12==c&&(e=12);return Cb(e,a,d)}}function Db(b,a){return function(c,
|
||||||
|
d){var e=c["get"+b](),f=rb(a?"SHORT"+b:b);return d[f][e]}}function md(b){var a=(new Date(b,0,1)).getDay();return new Date(b,0,(4>=a?5:12)-a)}function nd(b){return function(a){var c=md(a.getFullYear());a=+new Date(a.getFullYear(),a.getMonth(),a.getDate()+(4-a.getDay()))-+c;a=1+Math.round(a/6048E5);return Cb(a,b)}}function hd(b){function a(a){var b;if(b=a.match(c)){a=new Date(0);var f=0,g=0,h=b[8]?a.setUTCFullYear:a.setFullYear,k=b[8]?a.setUTCHours:a.setHours;b[9]&&(f=$(b[9]+b[10]),g=$(b[9]+b[11]));
|
||||||
|
h.call(a,$(b[1]),$(b[2])-1,$(b[3]));f=$(b[4]||0)-f;g=$(b[5]||0)-g;h=$(b[6]||0);b=Math.round(1E3*parseFloat("0."+(b[7]||0)));k.call(a,f,g,h,b)}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,e,f){var g="",h=[],k,l;e=e||"mediumDate";e=b.DATETIME_FORMATS[e]||e;I(c)&&(c=Ff.test(c)?$(c):a(c));X(c)&&(c=new Date(c));if(!fa(c))return c;for(;e;)(l=Gf.exec(e))?(h=Xa(h,l,1),e=h.pop()):(h.push(e),e=null);f&&"UTC"===f&&(c=
|
||||||
|
new Date(c.getTime()),c.setMinutes(c.getMinutes()+c.getTimezoneOffset()));r(h,function(a){k=Hf[a];g+=k?k(c,b.DATETIME_FORMATS):a.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function Bf(){return function(b){return Za(b,!0)}}function Cf(){return function(b,a){X(b)&&(b=b.toString());if(!D(b)&&!I(b))return b;a=Infinity===Math.abs(Number(a))?Number(a):$(a);if(I(b))return a?0<=a?b.slice(0,a):b.slice(a,b.length):"";var c=[],d,e;a>b.length?a=b.length:a<-b.length&&(a=-b.length);0<a?(d=0,e=a):(d=
|
||||||
|
b.length+a,e=b.length);for(;d<e;d++)c.push(b[d]);return c}}function jd(b){return function(a,c,d){function e(a,b){return b?function(b,c){return a(c,b)}:a}function f(a,b){var c=typeof a,d=typeof b;return c==d?(fa(a)&&fa(b)&&(a=a.valueOf(),b=b.valueOf()),"string"==c&&(a=a.toLowerCase(),b=b.toLowerCase()),a===b?0:a<b?-1:1):c<d?-1:1}if(!Ra(a))return a;c=D(c)?c:[c];0===c.length&&(c=["+"]);c=c.map(function(a){var c=!1,d=a||oa;if(I(a)){if("+"==a.charAt(0)||"-"==a.charAt(0))c="-"==a.charAt(0),a=a.substring(1);
|
||||||
|
if(""===a)return e(function(a,b){return f(a,b)},c);d=b(a);if(d.constant){var l=d();return e(function(a,b){return f(a[l],b[l])},c)}}return e(function(a,b){return f(d(a),d(b))},c)});return Ya.call(a).sort(e(function(a,b){for(var d=0;d<c.length;d++){var e=c[d](a,b);if(0!==e)return e}return 0},d))}}function Ia(b){F(b)&&(b={link:b});b.restrict=b.restrict||"AC";return ca(b)}function od(b,a,c,d,e){var f=this,g=[],h=f.$$parentForm=b.parent().controller("form")||Eb;f.$error={};f.$$success={};f.$pending=u;
|
||||||
|
f.$name=e(a.name||a.ngForm||"")(c);f.$dirty=!1;f.$pristine=!0;f.$valid=!0;f.$invalid=!1;f.$submitted=!1;h.$addControl(f);f.$rollbackViewValue=function(){r(g,function(a){a.$rollbackViewValue()})};f.$commitViewValue=function(){r(g,function(a){a.$commitViewValue()})};f.$addControl=function(a){La(a.$name,"input");g.push(a);a.$name&&(f[a.$name]=a)};f.$$renameControl=function(a,b){var c=a.$name;f[c]===a&&delete f[c];f[b]=a;a.$name=b};f.$removeControl=function(a){a.$name&&f[a.$name]===a&&delete f[a.$name];
|
||||||
|
r(f.$pending,function(b,c){f.$setValidity(c,null,a)});r(f.$error,function(b,c){f.$setValidity(c,null,a)});Va(g,a)};pd({ctrl:this,$element:b,set:function(a,b,c){var d=a[b];d?-1===d.indexOf(c)&&d.push(c):a[b]=[c]},unset:function(a,b,c){var d=a[b];d&&(Va(d,c),0===d.length&&delete a[b])},parentForm:h,$animate:d});f.$setDirty=function(){d.removeClass(b,Qa);d.addClass(b,Fb);f.$dirty=!0;f.$pristine=!1;h.$setDirty()};f.$setPristine=function(){d.setClass(b,Qa,Fb+" ng-submitted");f.$dirty=!1;f.$pristine=!0;
|
||||||
|
f.$submitted=!1;r(g,function(a){a.$setPristine()})};f.$setUntouched=function(){r(g,function(a){a.$setUntouched()})};f.$setSubmitted=function(){d.addClass(b,"ng-submitted");f.$submitted=!0;h.$setSubmitted()}}function hc(b){b.$formatters.push(function(a){return b.$isEmpty(a)?a:a.toString()})}function gb(b,a,c,d,e,f){var g=a[0].placeholder,h={},k=R(a[0].type);if(!e.android){var l=!1;a.on("compositionstart",function(a){l=!0});a.on("compositionend",function(){l=!1;m()})}var m=function(b){if(!l){var e=
|
||||||
|
a.val(),f=b&&b.type;Ha&&"input"===(b||h).type&&a[0].placeholder!==g?g=a[0].placeholder:("password"===k||c.ngTrim&&"false"===c.ngTrim||(e=P(e)),(d.$viewValue!==e||""===e&&d.$$hasNativeValidators)&&d.$setViewValue(e,f))}};if(e.hasEvent("input"))a.on("input",m);else{var p,s=function(a){p||(p=f.defer(function(){m(a);p=null}))};a.on("keydown",function(a){var b=a.keyCode;91===b||15<b&&19>b||37<=b&&40>=b||s(a)});if(e.hasEvent("paste"))a.on("paste cut",s)}a.on("change",m);d.$render=function(){a.val(d.$isEmpty(d.$viewValue)?
|
||||||
|
"":d.$viewValue)}}function Gb(b,a){return function(c,d){var e,f;if(fa(c))return c;if(I(c)){'"'==c.charAt(0)&&'"'==c.charAt(c.length-1)&&(c=c.substring(1,c.length-1));if(If.test(c))return new Date(c);b.lastIndex=0;if(e=b.exec(c))return e.shift(),f=d?{yyyy:d.getFullYear(),MM:d.getMonth()+1,dd:d.getDate(),HH:d.getHours(),mm:d.getMinutes(),ss:d.getSeconds(),sss:d.getMilliseconds()/1E3}:{yyyy:1970,MM:1,dd:1,HH:0,mm:0,ss:0,sss:0},r(e,function(b,c){c<a.length&&(f[a[c]]=+b)}),new Date(f.yyyy,f.MM-1,f.dd,
|
||||||
|
f.HH,f.mm,f.ss||0,1E3*f.sss||0)}return NaN}}function hb(b,a,c,d){return function(e,f,g,h,k,l,m){function p(a){return a&&!(a.getTime&&a.getTime()!==a.getTime())}function s(a){return y(a)?fa(a)?a:c(a):u}qd(e,f,g,h);gb(e,f,g,h,k,l);var t=h&&h.$options&&h.$options.timezone,q;h.$$parserName=b;h.$parsers.push(function(b){return h.$isEmpty(b)?null:a.test(b)?(b=c(b,q),"UTC"===t&&b.setMinutes(b.getMinutes()-b.getTimezoneOffset()),b):u});h.$formatters.push(function(a){if(a&&!fa(a))throw Hb("datefmt",a);if(p(a)){if((q=
|
||||||
|
a)&&"UTC"===t){var b=6E4*q.getTimezoneOffset();q=new Date(q.getTime()+b)}return m("date")(a,d,t)}q=null;return""});if(y(g.min)||g.ngMin){var r;h.$validators.min=function(a){return!p(a)||G(r)||c(a)>=r};g.$observe("min",function(a){r=s(a);h.$validate()})}if(y(g.max)||g.ngMax){var n;h.$validators.max=function(a){return!p(a)||G(n)||c(a)<=n};g.$observe("max",function(a){n=s(a);h.$validate()})}}}function qd(b,a,c,d){(d.$$hasNativeValidators=K(a[0].validity))&&d.$parsers.push(function(b){var c=a.prop("validity")||
|
||||||
|
{};return c.badInput&&!c.typeMismatch?u:b})}function rd(b,a,c,d,e){if(y(d)){b=b(d);if(!b.constant)throw z("ngModel")("constexpr",c,d);return b(a)}return e}function pd(b){function a(a,b){b&&!f[a]?(l.addClass(e,a),f[a]=!0):!b&&f[a]&&(l.removeClass(e,a),f[a]=!1)}function c(b,c){b=b?"-"+Mb(b,"-"):"";a(ib+b,!0===c);a(sd+b,!1===c)}var d=b.ctrl,e=b.$element,f={},g=b.set,h=b.unset,k=b.parentForm,l=b.$animate;f[sd]=!(f[ib]=e.hasClass(ib));d.$setValidity=function(b,e,f){e===u?(d.$pending||(d.$pending={}),g(d.$pending,
|
||||||
|
b,f)):(d.$pending&&h(d.$pending,b,f),td(d.$pending)&&(d.$pending=u));Ua(e)?e?(h(d.$error,b,f),g(d.$$success,b,f)):(g(d.$error,b,f),h(d.$$success,b,f)):(h(d.$error,b,f),h(d.$$success,b,f));d.$pending?(a(ud,!0),d.$valid=d.$invalid=u,c("",null)):(a(ud,!1),d.$valid=td(d.$error),d.$invalid=!d.$valid,c("",d.$valid));e=d.$pending&&d.$pending[b]?u:d.$error[b]?!1:d.$$success[b]?!0:null;c(b,e);k.$setValidity(b,e,d)}}function td(b){if(b)for(var a in b)return!1;return!0}function ic(b,a){b="ngClass"+b;return["$animate",
|
||||||
|
function(c){function d(a,b){var c=[],d=0;a:for(;d<a.length;d++){for(var e=a[d],m=0;m<b.length;m++)if(e==b[m])continue a;c.push(e)}return c}function e(a){if(!D(a)){if(I(a))return a.split(" ");if(K(a)){var b=[];r(a,function(a,c){a&&(b=b.concat(c.split(" ")))});return b}}return a}return{restrict:"AC",link:function(f,g,h){function k(a,b){var c=g.data("$classCounts")||{},d=[];r(a,function(a){if(0<b||c[a])c[a]=(c[a]||0)+b,c[a]===+(0<b)&&d.push(a)});g.data("$classCounts",c);return d.join(" ")}function l(b){if(!0===
|
||||||
|
a||f.$index%2===a){var l=e(b||[]);if(!m){var t=k(l,1);h.$addClass(t)}else if(!pa(b,m)){var q=e(m),t=d(l,q),l=d(q,l),t=k(t,1),l=k(l,-1);t&&t.length&&c.addClass(g,t);l&&l.length&&c.removeClass(g,l)}}m=ua(b)}var m;f.$watch(h[b],l,!0);h.$observe("class",function(a){l(f.$eval(h[b]))});"ngClass"!==b&&f.$watch("$index",function(c,d){var g=c&1;if(g!==(d&1)){var l=e(f.$eval(h[b]));g===a?(g=k(l,1),h.$addClass(g)):(g=k(l,-1),h.$removeClass(g))}})}}}]}var Jf=/^\/(.+)\/([a-z]*)$/,R=function(b){return I(b)?b.toLowerCase():
|
||||||
|
b},Jb=Object.prototype.hasOwnProperty,rb=function(b){return I(b)?b.toUpperCase():b},Ha,A,qa,Ya=[].slice,of=[].splice,Kf=[].push,Ja=Object.prototype.toString,Wa=z("ng"),ha=U.angular||(U.angular={}),ab,kb=0;Ha=V.documentMode;x.$inject=[];oa.$inject=[];var D=Array.isArray,P=function(b){return I(b)?b.trim():b},dd=function(b){return b.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g,"\\$1").replace(/\x08/g,"\\x08")},$a=function(){if(y($a.isActive_))return $a.isActive_;var b=!(!V.querySelector("[ng-csp]")&&!V.querySelector("[data-ng-csp]"));
|
||||||
|
if(!b)try{new Function("")}catch(a){b=!0}return $a.isActive_=b},ob=["ng-","data-ng-","ng:","x-ng-"],Jd=/[A-Z]/g,sc=!1,Nb,na=1,mb=3,Nd={full:"1.3.4",major:1,minor:3,dot:4,codeName:"highfalutin-petroglyph"};S.expando="ng339";var wb=S.cache={},df=1;S._data=function(b){return this.cache[b[this.expando]]||{}};var Ze=/([\:\-\_]+(.))/g,$e=/^moz([A-Z])/,Lf={mouseleave:"mouseout",mouseenter:"mouseover"},Qb=z("jqLite"),cf=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,Pb=/<|&#?\w+;/,af=/<([\w:]+)/,bf=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
|
||||||
|
ja={option:[1,'<select multiple="multiple">',"</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ja.optgroup=ja.option;ja.tbody=ja.tfoot=ja.colgroup=ja.caption=ja.thead;ja.th=ja.td;var Ka=S.prototype={ready:function(b){function a(){c||(c=!0,b())}var c=!1;"complete"===V.readyState?setTimeout(a):(this.on("DOMContentLoaded",a),S(U).on("load",a))},
|
||||||
|
toString:function(){var b=[];r(this,function(a){b.push(""+a)});return"["+b.join(", ")+"]"},eq:function(b){return 0<=b?A(this[b]):A(this[this.length+b])},length:0,push:Kf,sort:[].sort,splice:[].splice},yb={};r("multiple selected checked disabled readOnly required open".split(" "),function(b){yb[R(b)]=b});var Kc={};r("input select option textarea button form details".split(" "),function(b){Kc[b]=!0});var Lc={ngMinlength:"minlength",ngMaxlength:"maxlength",ngMin:"min",ngMax:"max",ngPattern:"pattern"};
|
||||||
|
r({data:Sb,removeData:ub},function(b,a){S[a]=b});r({data:Sb,inheritedData:xb,scope:function(b){return A.data(b,"$scope")||xb(b.parentNode||b,["$isolateScope","$scope"])},isolateScope:function(b){return A.data(b,"$isolateScope")||A.data(b,"$isolateScopeNoTemplate")},controller:Gc,injector:function(b){return xb(b,"$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:Tb,css:function(b,a,c){a=bb(a);if(y(c))b.style[a]=c;else return b.style[a]},attr:function(b,a,c){var d=R(a);if(yb[d])if(y(c))c?
|
||||||
|
(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));else return b[a]||(b.attributes.getNamedItem(a)||x).specified?d:u;else if(y(c))b.setAttribute(a,c);else if(b.getAttribute)return b=b.getAttribute(a,2),null===b?u:b},prop:function(b,a,c){if(y(c))b[a]=c;else return b[a]},text:function(){function b(a,b){if(G(b)){var d=a.nodeType;return d===na||d===mb?a.textContent:""}a.textContent=b}b.$dv="";return b}(),val:function(b,a){if(G(a)){if(b.multiple&&"select"===ta(b)){var c=[];r(b.options,function(a){a.selected&&
|
||||||
|
c.push(a.value||a.text)});return 0===c.length?null:c}return b.value}b.value=a},html:function(b,a){if(G(a))return b.innerHTML;tb(b,!0);b.innerHTML=a},empty:Hc},function(b,a){S.prototype[a]=function(a,d){var e,f,g=this.length;if(b!==Hc&&(2==b.length&&b!==Tb&&b!==Gc?a:d)===u){if(K(a)){for(e=0;e<g;e++)if(b===Sb)b(this[e],a);else for(f in a)b(this[e],f,a[f]);return this}e=b.$dv;g=e===u?Math.min(g,1):g;for(f=0;f<g;f++){var h=b(this[f],a,d);e=e?e+h:h}return e}for(e=0;e<g;e++)b(this[e],a,d);return this}});
|
||||||
|
r({removeData:ub,on:function a(c,d,e,f){if(y(f))throw Qb("onargs");if(Cc(c)){var g=vb(c,!0);f=g.events;var h=g.handle;h||(h=g.handle=gf(c,f));for(var g=0<=d.indexOf(" ")?d.split(" "):[d],k=g.length;k--;){d=g[k];var l=f[d];l||(f[d]=[],"mouseenter"===d||"mouseleave"===d?a(c,Lf[d],function(a){var c=a.relatedTarget;c&&(c===this||this.contains(c))||h(a,d)}):"$destroy"!==d&&c.addEventListener(d,h,!1),l=f[d]);l.push(e)}}},off:Fc,one:function(a,c,d){a=A(a);a.on(c,function f(){a.off(c,d);a.off(c,f)});a.on(c,
|
||||||
|
d)},replaceWith:function(a,c){var d,e=a.parentNode;tb(a);r(new S(c),function(c){d?e.insertBefore(c,d.nextSibling):e.replaceChild(c,a);d=c})},children:function(a){var c=[];r(a.childNodes,function(a){a.nodeType===na&&c.push(a)});return c},contents:function(a){return a.contentDocument||a.childNodes||[]},append:function(a,c){var d=a.nodeType;if(d===na||11===d){c=new S(c);for(var d=0,e=c.length;d<e;d++)a.appendChild(c[d])}},prepend:function(a,c){if(a.nodeType===na){var d=a.firstChild;r(new S(c),function(c){a.insertBefore(c,
|
||||||
|
d)})}},wrap:function(a,c){c=A(c).eq(0).clone()[0];var d=a.parentNode;d&&d.replaceChild(c,a);c.appendChild(a)},remove:Ic,detach:function(a){Ic(a,!0)},after:function(a,c){var d=a,e=a.parentNode;c=new S(c);for(var f=0,g=c.length;f<g;f++){var h=c[f];e.insertBefore(h,d.nextSibling);d=h}},addClass:Vb,removeClass:Ub,toggleClass:function(a,c,d){c&&r(c.split(" "),function(c){var f=d;G(f)&&(f=!Tb(a,c));(f?Vb:Ub)(a,c)})},parent:function(a){return(a=a.parentNode)&&11!==a.nodeType?a:null},next:function(a){return a.nextElementSibling},
|
||||||
|
find:function(a,c){return a.getElementsByTagName?a.getElementsByTagName(c):[]},clone:Rb,triggerHandler:function(a,c,d){var e,f,g=c.type||c,h=vb(a);if(h=(h=h&&h.events)&&h[g])e={preventDefault:function(){this.defaultPrevented=!0},isDefaultPrevented:function(){return!0===this.defaultPrevented},stopImmediatePropagation:function(){this.immediatePropagationStopped=!0},isImmediatePropagationStopped:function(){return!0===this.immediatePropagationStopped},stopPropagation:x,type:g,target:a},c.type&&(e=C(e,
|
||||||
|
c)),c=ua(h),f=d?[e].concat(d):[e],r(c,function(c){e.isImmediatePropagationStopped()||c.apply(a,f)})}},function(a,c){S.prototype[c]=function(c,e,f){for(var g,h=0,k=this.length;h<k;h++)G(g)?(g=a(this[h],c,e,f),y(g)&&(g=A(g))):Ec(g,a(this[h],c,e,f));return y(g)?g:this};S.prototype.bind=S.prototype.on;S.prototype.unbind=S.prototype.off});cb.prototype={put:function(a,c){this[Ma(a,this.nextUid)]=c},get:function(a){return this[Ma(a,this.nextUid)]},remove:function(a){var c=this[a=Ma(a,this.nextUid)];delete this[a];
|
||||||
|
return c}};var Nc=/^function\s*[^\(]*\(\s*([^\)]*)\)/m,jf=/,/,kf=/^\s*(_?)(\S+?)\1\s*$/,Mc=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,Ea=z("$injector");Lb.$$annotate=Wb;var Mf=z("$animate"),ze=["$provide",function(a){this.$$selectors={};this.register=function(c,d){var e=c+"-animation";if(c&&"."!=c.charAt(0))throw Mf("notcsel",c);this.$$selectors[c.substr(1)]=e;a.factory(e,d)};this.classNameFilter=function(a){1===arguments.length&&(this.$$classNameFilter=a instanceof RegExp?a:null);return this.$$classNameFilter};
|
||||||
|
this.$get=["$$q","$$asyncCallback","$rootScope",function(a,d,e){function f(d){var f,g=a.defer();g.promise.$$cancelFn=function(){f&&f()};e.$$postDigest(function(){f=d(function(){g.resolve()})});return g.promise}function g(a,c){var d=[],e=[],f=ia();r((a.attr("class")||"").split(/\s+/),function(a){f[a]=!0});r(c,function(a,c){var g=f[c];!1===a&&g?e.push(c):!0!==a||g||d.push(c)});return 0<d.length+e.length&&[d.length?d:null,e.length?e:null]}function h(a,c,d){for(var e=0,f=c.length;e<f;++e)a[c[e]]=d}function k(){m||
|
||||||
|
(m=a.defer(),d(function(){m.resolve();m=null}));return m.promise}function l(a,c){if(ha.isObject(c)){var d=C(c.from||{},c.to||{});a.css(d)}}var m;return{animate:function(a,c,d){l(a,{from:c,to:d});return k()},enter:function(a,c,d,e){l(a,e);d?d.after(a):c.prepend(a);return k()},leave:function(a,c){a.remove();return k()},move:function(a,c,d,e){return this.enter(a,c,d,e)},addClass:function(a,c,d){return this.setClass(a,c,[],d)},$$addClassImmediately:function(a,c,d){a=A(a);c=I(c)?c:D(c)?c.join(" "):"";
|
||||||
|
r(a,function(a){Vb(a,c)});l(a,d);return k()},removeClass:function(a,c,d){return this.setClass(a,[],c,d)},$$removeClassImmediately:function(a,c,d){a=A(a);c=I(c)?c:D(c)?c.join(" "):"";r(a,function(a){Ub(a,c)});l(a,d);return k()},setClass:function(a,c,d,e){var k=this,l=!1;a=A(a);var m=a.data("$$animateClasses");m?e&&m.options&&(m.options=ha.extend(m.options||{},e)):(m={classes:{},options:e},l=!0);e=m.classes;c=D(c)?c:c.split(" ");d=D(d)?d:d.split(" ");h(e,c,!0);h(e,d,!1);l&&(m.promise=f(function(c){var d=
|
||||||
|
a.data("$$animateClasses");a.removeData("$$animateClasses");if(d){var e=g(a,d.classes);e&&k.$$setClassImmediately(a,e[0],e[1],d.options)}c()}),a.data("$$animateClasses",m));return m.promise},$$setClassImmediately:function(a,c,d,e){c&&this.$$addClassImmediately(a,c);d&&this.$$removeClassImmediately(a,d);l(a,e);return k()},enabled:x,cancel:x}}]}],ka=z("$compile");uc.$inject=["$provide","$$sanitizeUriProvider"];var nf=/^((?:x|data)[\:\-_])/i,Sc="application/json",Zb={"Content-Type":Sc+";charset=utf-8"},
|
||||||
|
qf=/^\s*(\[|\{[^\{])/,rf=/[\}\]]\s*$/,pf=/^\)\]\}',?\n/,$b=z("$interpolate"),Nf=/^([^\?#]*)(\?([^#]*))?(#(.*))?$/,uf={http:80,https:443,ftp:21},eb=z("$location"),Of={$$html5:!1,$$replace:!1,absUrl:Bb("$$absUrl"),url:function(a){if(G(a))return this.$$url;var c=Nf.exec(a);(c[1]||""===a)&&this.path(decodeURIComponent(c[1]));(c[2]||c[1]||""===a)&&this.search(c[3]||"");this.hash(c[5]||"");return this},protocol:Bb("$$protocol"),host:Bb("$$host"),port:Bb("$$port"),path:$c("$$path",function(a){a=null!==a?
|
||||||
|
a.toString():"";return"/"==a.charAt(0)?a:"/"+a}),search:function(a,c){switch(arguments.length){case 0:return this.$$search;case 1:if(I(a)||X(a))a=a.toString(),this.$$search=qc(a);else if(K(a))a=Ca(a,{}),r(a,function(c,e){null==c&&delete a[e]}),this.$$search=a;else throw eb("isrcharg");break;default:G(c)||null===c?delete this.$$search[a]:this.$$search[a]=c}this.$$compose();return this},hash:$c("$$hash",function(a){return null!==a?a.toString():""}),replace:function(){this.$$replace=!0;return this}};
|
||||||
|
r([Zc,dc,cc],function(a){a.prototype=Object.create(Of);a.prototype.state=function(c){if(!arguments.length)return this.$$state;if(a!==cc||!this.$$html5)throw eb("nostate");this.$$state=G(c)?null:c;return this}});var la=z("$parse"),Pf=Function.prototype.call,Qf=Function.prototype.apply,Rf=Function.prototype.bind,Ib=ia();r({"null":function(){return null},"true":function(){return!0},"false":function(){return!1},undefined:function(){}},function(a,c){a.constant=a.literal=a.sharedGetter=!0;Ib[c]=a});Ib["this"]=
|
||||||
|
function(a){return a};Ib["this"].sharedGetter=!0;var jb=C(ia(),{"+":function(a,c,d,e){d=d(a,c);e=e(a,c);return y(d)?y(e)?d+e:d:y(e)?e:u},"-":function(a,c,d,e){d=d(a,c);e=e(a,c);return(y(d)?d:0)-(y(e)?e:0)},"*":function(a,c,d,e){return d(a,c)*e(a,c)},"/":function(a,c,d,e){return d(a,c)/e(a,c)},"%":function(a,c,d,e){return d(a,c)%e(a,c)},"===":function(a,c,d,e){return d(a,c)===e(a,c)},"!==":function(a,c,d,e){return d(a,c)!==e(a,c)},"==":function(a,c,d,e){return d(a,c)==e(a,c)},"!=":function(a,c,d,e){return d(a,
|
||||||
|
c)!=e(a,c)},"<":function(a,c,d,e){return d(a,c)<e(a,c)},">":function(a,c,d,e){return d(a,c)>e(a,c)},"<=":function(a,c,d,e){return d(a,c)<=e(a,c)},">=":function(a,c,d,e){return d(a,c)>=e(a,c)},"&&":function(a,c,d,e){return d(a,c)&&e(a,c)},"||":function(a,c,d,e){return d(a,c)||e(a,c)},"!":function(a,c,d){return!d(a,c)},"=":!0,"|":!0}),Sf={n:"\n",f:"\f",r:"\r",t:"\t",v:"\v","'":"'",'"':'"'},gc=function(a){this.options=a};gc.prototype={constructor:gc,lex:function(a){this.text=a;this.index=0;for(this.tokens=
|
||||||
|
[];this.index<this.text.length;)if(a=this.text.charAt(this.index),'"'===a||"'"===a)this.readString(a);else if(this.isNumber(a)||"."===a&&this.isNumber(this.peek()))this.readNumber();else if(this.isIdent(a))this.readIdent();else if(this.is(a,"(){}[].,;:?"))this.tokens.push({index:this.index,text:a}),this.index++;else if(this.isWhitespace(a))this.index++;else{var c=a+this.peek(),d=c+this.peek(2),e=jb[c],f=jb[d];jb[a]||e||f?(a=f?d:e?c:a,this.tokens.push({index:this.index,text:a,operator:!0}),this.index+=
|
||||||
|
a.length):this.throwError("Unexpected next character ",this.index,this.index+1)}return this.tokens},is:function(a,c){return-1!==c.indexOf(a)},peek:function(a){a=a||1;return this.index+a<this.text.length?this.text.charAt(this.index+a):!1},isNumber:function(a){return"0"<=a&&"9">=a&&"string"===typeof a},isWhitespace:function(a){return" "===a||"\r"===a||"\t"===a||"\n"===a||"\v"===a||"\u00a0"===a},isIdent:function(a){return"a"<=a&&"z">=a||"A"<=a&&"Z">=a||"_"===a||"$"===a},isExpOperator:function(a){return"-"===
|
||||||
|
a||"+"===a||this.isNumber(a)},throwError:function(a,c,d){d=d||this.index;c=y(c)?"s "+c+"-"+this.index+" ["+this.text.substring(c,d)+"]":" "+d;throw la("lexerr",a,c,this.text);},readNumber:function(){for(var a="",c=this.index;this.index<this.text.length;){var d=R(this.text.charAt(this.index));if("."==d||this.isNumber(d))a+=d;else{var e=this.peek();if("e"==d&&this.isExpOperator(e))a+=d;else if(this.isExpOperator(d)&&e&&this.isNumber(e)&&"e"==a.charAt(a.length-1))a+=d;else if(!this.isExpOperator(d)||
|
||||||
|
e&&this.isNumber(e)||"e"!=a.charAt(a.length-1))break;else this.throwError("Invalid exponent")}this.index++}this.tokens.push({index:c,text:a,constant:!0,value:Number(a)})},readIdent:function(){for(var a=this.index;this.index<this.text.length;){var c=this.text.charAt(this.index);if(!this.isIdent(c)&&!this.isNumber(c))break;this.index++}this.tokens.push({index:a,text:this.text.slice(a,this.index),identifier:!0})},readString:function(a){var c=this.index;this.index++;for(var d="",e=a,f=!1;this.index<this.text.length;){var g=
|
||||||
|
this.text.charAt(this.index),e=e+g;if(f)"u"===g?(f=this.text.substring(this.index+1,this.index+5),f.match(/[\da-f]{4}/i)||this.throwError("Invalid unicode escape [\\u"+f+"]"),this.index+=4,d+=String.fromCharCode(parseInt(f,16))):d+=Sf[g]||g,f=!1;else if("\\"===g)f=!0;else{if(g===a){this.index++;this.tokens.push({index:c,text:e,constant:!0,value:d});return}d+=g}this.index++}this.throwError("Unterminated quote",c)}};var fb=function(a,c,d){this.lexer=a;this.$filter=c;this.options=d};fb.ZERO=C(function(){return 0},
|
||||||
|
{sharedGetter:!0,constant:!0});fb.prototype={constructor:fb,parse:function(a){this.text=a;this.tokens=this.lexer.lex(a);a=this.statements();0!==this.tokens.length&&this.throwError("is an unexpected token",this.tokens[0]);a.literal=!!a.literal;a.constant=!!a.constant;return a},primary:function(){var a;this.expect("(")?(a=this.filterChain(),this.consume(")")):this.expect("[")?a=this.arrayDeclaration():this.expect("{")?a=this.object():this.peek().identifier?a=this.identifier():this.peek().constant?a=
|
||||||
|
this.constant():this.throwError("not a primary expression",this.peek());for(var c,d;c=this.expect("(","[",".");)"("===c.text?(a=this.functionCall(a,d),d=null):"["===c.text?(d=a,a=this.objectIndex(a)):"."===c.text?(d=a,a=this.fieldAccess(a)):this.throwError("IMPOSSIBLE");return a},throwError:function(a,c){throw la("syntax",c.text,a,c.index+1,this.text,this.text.substring(c.index));},peekToken:function(){if(0===this.tokens.length)throw la("ueoe",this.text);return this.tokens[0]},peek:function(a,c,d,
|
||||||
|
e){return this.peekAhead(0,a,c,d,e)},peekAhead:function(a,c,d,e,f){if(this.tokens.length>a){a=this.tokens[a];var g=a.text;if(g===c||g===d||g===e||g===f||!(c||d||e||f))return a}return!1},expect:function(a,c,d,e){return(a=this.peek(a,c,d,e))?(this.tokens.shift(),a):!1},consume:function(a){if(0===this.tokens.length)throw la("ueoe",this.text);var c=this.expect(a);c||this.throwError("is unexpected, expecting ["+a+"]",this.peek());return c},unaryFn:function(a,c){var d=jb[a];return C(function(a,f){return d(a,
|
||||||
|
f,c)},{constant:c.constant,inputs:[c]})},binaryFn:function(a,c,d,e){var f=jb[c];return C(function(c,e){return f(c,e,a,d)},{constant:a.constant&&d.constant,inputs:!e&&[a,d]})},identifier:function(){for(var a=this.consume().text;this.peek(".")&&this.peekAhead(1).identifier&&!this.peekAhead(2,"(");)a+=this.consume().text+this.consume().text;return Ib[a]||bd(a,this.options,this.text)},constant:function(){var a=this.consume().value;return C(function(){return a},{constant:!0,literal:!0})},statements:function(){for(var a=
|
||||||
|
[];;)if(0<this.tokens.length&&!this.peek("}",")",";","]")&&a.push(this.filterChain()),!this.expect(";"))return 1===a.length?a[0]:function(c,d){for(var e,f=0,g=a.length;f<g;f++)e=a[f](c,d);return e}},filterChain:function(){for(var a=this.expression();this.expect("|");)a=this.filter(a);return a},filter:function(a){var c=this.$filter(this.consume().text),d,e;if(this.peek(":"))for(d=[],e=[];this.expect(":");)d.push(this.expression());var f=[a].concat(d||[]);return C(function(f,h){var k=a(f,h);if(e){e[0]=
|
||||||
|
k;for(k=d.length;k--;)e[k+1]=d[k](f,h);return c.apply(u,e)}return c(k)},{constant:!c.$stateful&&f.every(ec),inputs:!c.$stateful&&f})},expression:function(){return this.assignment()},assignment:function(){var a=this.ternary(),c,d;return(d=this.expect("="))?(a.assign||this.throwError("implies assignment but ["+this.text.substring(0,d.index)+"] can not be assigned to",d),c=this.ternary(),C(function(d,f){return a.assign(d,c(d,f),f)},{inputs:[a,c]})):a},ternary:function(){var a=this.logicalOR(),c;if(this.expect("?")&&
|
||||||
|
(c=this.assignment(),this.consume(":"))){var d=this.assignment();return C(function(e,f){return a(e,f)?c(e,f):d(e,f)},{constant:a.constant&&c.constant&&d.constant})}return a},logicalOR:function(){for(var a=this.logicalAND(),c;c=this.expect("||");)a=this.binaryFn(a,c.text,this.logicalAND(),!0);return a},logicalAND:function(){var a=this.equality(),c;if(c=this.expect("&&"))a=this.binaryFn(a,c.text,this.logicalAND(),!0);return a},equality:function(){var a=this.relational(),c;if(c=this.expect("==","!=",
|
||||||
|
"===","!=="))a=this.binaryFn(a,c.text,this.equality());return a},relational:function(){var a=this.additive(),c;if(c=this.expect("<",">","<=",">="))a=this.binaryFn(a,c.text,this.relational());return a},additive:function(){for(var a=this.multiplicative(),c;c=this.expect("+","-");)a=this.binaryFn(a,c.text,this.multiplicative());return a},multiplicative:function(){for(var a=this.unary(),c;c=this.expect("*","/","%");)a=this.binaryFn(a,c.text,this.unary());return a},unary:function(){var a;return this.expect("+")?
|
||||||
|
this.primary():(a=this.expect("-"))?this.binaryFn(fb.ZERO,a.text,this.unary()):(a=this.expect("!"))?this.unaryFn(a.text,this.unary()):this.primary()},fieldAccess:function(a){var c=this.text,d=this.consume().text,e=bd(d,this.options,c);return C(function(c,d,h){return e(h||a(c,d))},{assign:function(e,g,h){(h=a(e,h))||a.assign(e,h={});return Oa(h,d,g,c)}})},objectIndex:function(a){var c=this.text,d=this.expression();this.consume("]");return C(function(e,f){var g=a(e,f),h=d(e,f);ra(h,c);return g?sa(g[h],
|
||||||
|
c):u},{assign:function(e,f,g){var h=ra(d(e,g),c);(g=sa(a(e,g),c))||a.assign(e,g={});return g[h]=f}})},functionCall:function(a,c){var d=[];if(")"!==this.peekToken().text){do d.push(this.expression());while(this.expect(","))}this.consume(")");var e=this.text,f=d.length?[]:null;return function(g,h){var k=c?c(g,h):g,l=a(g,h,k)||x;if(f)for(var m=d.length;m--;)f[m]=sa(d[m](g,h),e);sa(k,e);if(l){if(l.constructor===l)throw la("isecfn",e);if(l===Pf||l===Qf||l===Rf)throw la("isecff",e);}k=l.apply?l.apply(k,
|
||||||
|
f):l(f[0],f[1],f[2],f[3],f[4]);return sa(k,e)}},arrayDeclaration:function(){var a=[];if("]"!==this.peekToken().text){do{if(this.peek("]"))break;a.push(this.expression())}while(this.expect(","))}this.consume("]");return C(function(c,d){for(var e=[],f=0,g=a.length;f<g;f++)e.push(a[f](c,d));return e},{literal:!0,constant:a.every(ec),inputs:a})},object:function(){var a=[],c=[];if("}"!==this.peekToken().text){do{if(this.peek("}"))break;var d=this.consume();d.constant?a.push(d.value):d.identifier?a.push(d.text):
|
||||||
|
this.throwError("invalid key",d);this.consume(":");c.push(this.expression())}while(this.expect(","))}this.consume("}");return C(function(d,f){for(var g={},h=0,k=c.length;h<k;h++)g[a[h]]=c[h](d,f);return g},{literal:!0,constant:c.every(ec),inputs:c})}};var xf=ia(),wf=ia(),yf=Object.prototype.valueOf,Ba=z("$sce"),ma={HTML:"html",CSS:"css",URL:"url",RESOURCE_URL:"resourceUrl",JS:"js"},ka=z("$compile"),Y=V.createElement("a"),fd=Aa(U.location.href);Bc.$inject=["$provide"];gd.$inject=["$locale"];id.$inject=
|
||||||
|
["$locale"];var ld=".",Hf={yyyy:Z("FullYear",4),yy:Z("FullYear",2,0,!0),y:Z("FullYear",1),MMMM:Db("Month"),MMM:Db("Month",!0),MM:Z("Month",2,1),M:Z("Month",1,1),dd:Z("Date",2),d:Z("Date",1),HH:Z("Hours",2),H:Z("Hours",1),hh:Z("Hours",2,-12),h:Z("Hours",1,-12),mm:Z("Minutes",2),m:Z("Minutes",1),ss:Z("Seconds",2),s:Z("Seconds",1),sss:Z("Milliseconds",3),EEEE:Db("Day"),EEE:Db("Day",!0),a:function(a,c){return 12>a.getHours()?c.AMPMS[0]:c.AMPMS[1]},Z:function(a){a=-1*a.getTimezoneOffset();return a=(0<=
|
||||||
|
a?"+":"")+(Cb(Math[0<a?"floor":"ceil"](a/60),2)+Cb(Math.abs(a%60),2))},ww:nd(2),w:nd(1)},Gf=/((?:[^yMdHhmsaZEw']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|w+))(.*)/,Ff=/^\-?\d+$/;hd.$inject=["$locale"];var Df=ca(R),Ef=ca(rb);jd.$inject=["$parse"];var Qd=ca({restrict:"E",compile:function(a,c){if(!c.href&&!c.xlinkHref&&!c.name)return function(a,c){var f="[object SVGAnimatedString]"===Ja.call(c.prop("href"))?"xlink:href":"href";c.on("click",function(a){c.attr(f)||a.preventDefault()})}}}),sb=
|
||||||
|
{};r(yb,function(a,c){if("multiple"!=a){var d=wa("ng-"+c);sb[d]=function(){return{restrict:"A",priority:100,link:function(a,f,g){a.$watch(g[d],function(a){g.$set(c,!!a)})}}}}});r(Lc,function(a,c){sb[c]=function(){return{priority:100,link:function(a,e,f){if("ngPattern"===c&&"/"==f.ngPattern.charAt(0)&&(e=f.ngPattern.match(Jf))){f.$set("ngPattern",new RegExp(e[1],e[2]));return}a.$watch(f[c],function(a){f.$set(c,a)})}}}});r(["src","srcset","href"],function(a){var c=wa("ng-"+a);sb[c]=function(){return{priority:99,
|
||||||
|
link:function(d,e,f){var g=a,h=a;"href"===a&&"[object SVGAnimatedString]"===Ja.call(e.prop("href"))&&(h="xlinkHref",f.$attr[h]="xlink:href",g=null);f.$observe(c,function(c){c?(f.$set(h,c),Ha&&g&&e.prop(g,f[h])):"href"===a&&f.$set(h,null)})}}}});var Eb={$addControl:x,$$renameControl:function(a,c){a.$name=c},$removeControl:x,$setValidity:x,$setDirty:x,$setPristine:x,$setSubmitted:x};od.$inject=["$element","$attrs","$scope","$animate","$interpolate"];var vd=function(a){return["$timeout",function(c){return{name:"form",
|
||||||
|
restrict:a?"EAC":"E",controller:od,compile:function(a){a.addClass(Qa).addClass(ib);return{pre:function(a,d,g,h){if(!("action"in g)){var k=function(c){a.$apply(function(){h.$commitViewValue();h.$setSubmitted()});c.preventDefault()};d[0].addEventListener("submit",k,!1);d.on("$destroy",function(){c(function(){d[0].removeEventListener("submit",k,!1)},0,!1)})}var l=h.$$parentForm,m=h.$name;m&&(Oa(a,m,h,m),g.$observe(g.name?"name":"ngForm",function(c){m!==c&&(Oa(a,m,u,m),m=c,Oa(a,m,h,m),l.$$renameControl(h,
|
||||||
|
m))}));d.on("$destroy",function(){l.$removeControl(h);m&&Oa(a,m,u,m);C(h,Eb)})}}}}}]},Rd=vd(),de=vd(!0),If=/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/,Tf=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,Uf=/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i,Vf=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/,wd=/^(\d{4})-(\d{2})-(\d{2})$/,xd=/^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,
|
||||||
|
jc=/^(\d{4})-W(\d\d)$/,yd=/^(\d{4})-(\d\d)$/,zd=/^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,Wf=/(\s+|^)default(\s+|$)/,Hb=new z("ngModel"),Ad={text:function(a,c,d,e,f,g){gb(a,c,d,e,f,g);hc(e)},date:hb("date",wd,Gb(wd,["yyyy","MM","dd"]),"yyyy-MM-dd"),"datetime-local":hb("datetimelocal",xd,Gb(xd,"yyyy MM dd HH mm ss sss".split(" ")),"yyyy-MM-ddTHH:mm:ss.sss"),time:hb("time",zd,Gb(zd,["HH","mm","ss","sss"]),"HH:mm:ss.sss"),week:hb("week",jc,function(a,c){if(fa(a))return a;if(I(a)){jc.lastIndex=0;var d=
|
||||||
|
jc.exec(a);if(d){var e=+d[1],f=+d[2],g=d=0,h=0,k=0,l=md(e),f=7*(f-1);c&&(d=c.getHours(),g=c.getMinutes(),h=c.getSeconds(),k=c.getMilliseconds());return new Date(e,0,l.getDate()+f,d,g,h,k)}}return NaN},"yyyy-Www"),month:hb("month",yd,Gb(yd,["yyyy","MM"]),"yyyy-MM"),number:function(a,c,d,e,f,g){qd(a,c,d,e);gb(a,c,d,e,f,g);e.$$parserName="number";e.$parsers.push(function(a){return e.$isEmpty(a)?null:Vf.test(a)?parseFloat(a):u});e.$formatters.push(function(a){if(!e.$isEmpty(a)){if(!X(a))throw Hb("numfmt",
|
||||||
|
a);a=a.toString()}return a});if(d.min||d.ngMin){var h;e.$validators.min=function(a){return e.$isEmpty(a)||G(h)||a>=h};d.$observe("min",function(a){y(a)&&!X(a)&&(a=parseFloat(a,10));h=X(a)&&!isNaN(a)?a:u;e.$validate()})}if(d.max||d.ngMax){var k;e.$validators.max=function(a){return e.$isEmpty(a)||G(k)||a<=k};d.$observe("max",function(a){y(a)&&!X(a)&&(a=parseFloat(a,10));k=X(a)&&!isNaN(a)?a:u;e.$validate()})}},url:function(a,c,d,e,f,g){gb(a,c,d,e,f,g);hc(e);e.$$parserName="url";e.$validators.url=function(a,
|
||||||
|
c){var d=a||c;return e.$isEmpty(d)||Tf.test(d)}},email:function(a,c,d,e,f,g){gb(a,c,d,e,f,g);hc(e);e.$$parserName="email";e.$validators.email=function(a,c){var d=a||c;return e.$isEmpty(d)||Uf.test(d)}},radio:function(a,c,d,e){G(d.name)&&c.attr("name",++kb);c.on("click",function(a){c[0].checked&&e.$setViewValue(d.value,a&&a.type)});e.$render=function(){c[0].checked=d.value==e.$viewValue};d.$observe("value",e.$render)},checkbox:function(a,c,d,e,f,g,h,k){var l=rd(k,a,"ngTrueValue",d.ngTrueValue,!0),
|
||||||
|
m=rd(k,a,"ngFalseValue",d.ngFalseValue,!1);c.on("click",function(a){e.$setViewValue(c[0].checked,a&&a.type)});e.$render=function(){c[0].checked=e.$viewValue};e.$isEmpty=function(a){return!1===a};e.$formatters.push(function(a){return pa(a,l)});e.$parsers.push(function(a){return a?l:m})},hidden:x,button:x,submit:x,reset:x,file:x},vc=["$browser","$sniffer","$filter","$parse",function(a,c,d,e){return{restrict:"E",require:["?ngModel"],link:{pre:function(f,g,h,k){k[0]&&(Ad[R(h.type)]||Ad.text)(f,g,h,k[0],
|
||||||
|
c,a,d,e)}}}}],ib="ng-valid",sd="ng-invalid",Qa="ng-pristine",Fb="ng-dirty",ud="ng-pending",Xf=["$scope","$exceptionHandler","$attrs","$element","$parse","$animate","$timeout","$rootScope","$q","$interpolate",function(a,c,d,e,f,g,h,k,l,m){this.$modelValue=this.$viewValue=Number.NaN;this.$$rawModelValue=u;this.$validators={};this.$asyncValidators={};this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$untouched=!0;this.$touched=!1;this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=
|
||||||
|
!1;this.$error={};this.$$success={};this.$pending=u;this.$name=m(d.name||"",!1)(a);var p=f(d.ngModel),s=p.assign,t=p,q=s,N=null,n=this;this.$$setOptions=function(a){if((n.$options=a)&&a.getterSetter){var c=f(d.ngModel+"()"),g=f(d.ngModel+"($$$p)");t=function(a){var d=p(a);F(d)&&(d=c(a));return d};q=function(a,c){F(p(a))?g(a,{$$$p:n.$modelValue}):s(a,n.$modelValue)}}else if(!p.assign)throw Hb("nonassign",d.ngModel,va(e));};this.$render=x;this.$isEmpty=function(a){return G(a)||""===a||null===a||a!==
|
||||||
|
a};var v=e.inheritedData("$formController")||Eb,w=0;pd({ctrl:this,$element:e,set:function(a,c){a[c]=!0},unset:function(a,c){delete a[c]},parentForm:v,$animate:g});this.$setPristine=function(){n.$dirty=!1;n.$pristine=!0;g.removeClass(e,Fb);g.addClass(e,Qa)};this.$setDirty=function(){n.$dirty=!0;n.$pristine=!1;g.removeClass(e,Qa);g.addClass(e,Fb);v.$setDirty()};this.$setUntouched=function(){n.$touched=!1;n.$untouched=!0;g.setClass(e,"ng-untouched","ng-touched")};this.$setTouched=function(){n.$touched=
|
||||||
|
!0;n.$untouched=!1;g.setClass(e,"ng-touched","ng-untouched")};this.$rollbackViewValue=function(){h.cancel(N);n.$viewValue=n.$$lastCommittedViewValue;n.$render()};this.$validate=function(){if(!X(n.$modelValue)||!isNaN(n.$modelValue)){var a=n.$$rawModelValue,c=n.$valid,d=n.$modelValue,e=n.$options&&n.$options.allowInvalid;n.$$runValidators(n.$error[n.$$parserName||"parse"]?!1:u,a,n.$$lastCommittedViewValue,function(f){e||c===f||(n.$modelValue=f?a:u,n.$modelValue!==d&&n.$$writeModelToScope())})}};this.$$runValidators=
|
||||||
|
function(a,c,d,e){function f(){var a=!0;r(n.$validators,function(e,f){var g=e(c,d);a=a&&g;h(f,g)});return a?!0:(r(n.$asyncValidators,function(a,c){h(c,null)}),!1)}function g(){var a=[],e=!0;r(n.$asyncValidators,function(f,g){var k=f(c,d);if(!k||!F(k.then))throw Hb("$asyncValidators",k);h(g,u);a.push(k.then(function(){h(g,!0)},function(a){e=!1;h(g,!1)}))});a.length?l.all(a).then(function(){k(e)},x):k(!0)}function h(a,c){m===w&&n.$setValidity(a,c)}function k(a){m===w&&e(a)}w++;var m=w;(function(a){var c=
|
||||||
|
n.$$parserName||"parse";if(a===u)h(c,null);else if(h(c,a),!a)return r(n.$validators,function(a,c){h(c,null)}),r(n.$asyncValidators,function(a,c){h(c,null)}),!1;return!0})(a)?f()?g():k(!1):k(!1)};this.$commitViewValue=function(){var a=n.$viewValue;h.cancel(N);if(n.$$lastCommittedViewValue!==a||""===a&&n.$$hasNativeValidators)n.$$lastCommittedViewValue=a,n.$pristine&&this.$setDirty(),this.$$parseAndValidate()};this.$$parseAndValidate=function(){var c=n.$$lastCommittedViewValue,d=c,e=G(d)?u:!0;if(e)for(var f=
|
||||||
|
0;f<n.$parsers.length;f++)if(d=n.$parsers[f](d),G(d)){e=!1;break}X(n.$modelValue)&&isNaN(n.$modelValue)&&(n.$modelValue=t(a));var g=n.$modelValue,h=n.$options&&n.$options.allowInvalid;n.$$rawModelValue=d;h&&(n.$modelValue=d,n.$modelValue!==g&&n.$$writeModelToScope());n.$$runValidators(e,d,c,function(a){h||(n.$modelValue=a?d:u,n.$modelValue!==g&&n.$$writeModelToScope())})};this.$$writeModelToScope=function(){q(a,n.$modelValue);r(n.$viewChangeListeners,function(a){try{a()}catch(d){c(d)}})};this.$setViewValue=
|
||||||
|
function(a,c){n.$viewValue=a;n.$options&&!n.$options.updateOnDefault||n.$$debounceViewValueCommit(c)};this.$$debounceViewValueCommit=function(c){var d=0,e=n.$options;e&&y(e.debounce)&&(e=e.debounce,X(e)?d=e:X(e[c])?d=e[c]:X(e["default"])&&(d=e["default"]));h.cancel(N);d?N=h(function(){n.$commitViewValue()},d):k.$$phase?n.$commitViewValue():a.$apply(function(){n.$commitViewValue()})};a.$watch(function(){var c=t(a);if(c!==n.$modelValue){n.$modelValue=n.$$rawModelValue=c;for(var d=n.$formatters,e=d.length,
|
||||||
|
f=c;e--;)f=d[e](f);n.$viewValue!==f&&(n.$viewValue=n.$$lastCommittedViewValue=f,n.$render(),n.$$runValidators(u,c,f,x))}return c})}],se=["$rootScope",function(a){return{restrict:"A",require:["ngModel","^?form","^?ngModelOptions"],controller:Xf,priority:1,compile:function(c){c.addClass(Qa).addClass("ng-untouched").addClass(ib);return{pre:function(a,c,f,g){var h=g[0],k=g[1]||Eb;h.$$setOptions(g[2]&&g[2].$options);k.$addControl(h);f.$observe("name",function(a){h.$name!==a&&k.$$renameControl(h,a)});a.$on("$destroy",
|
||||||
|
function(){k.$removeControl(h)})},post:function(c,e,f,g){var h=g[0];if(h.$options&&h.$options.updateOn)e.on(h.$options.updateOn,function(a){h.$$debounceViewValueCommit(a&&a.type)});e.on("blur",function(e){h.$touched||(a.$$phase?c.$evalAsync(h.$setTouched):c.$apply(h.$setTouched))})}}}}}],ue=ca({restrict:"A",require:"ngModel",link:function(a,c,d,e){e.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),xc=function(){return{restrict:"A",require:"?ngModel",link:function(a,c,d,e){e&&(d.required=
|
||||||
|
!0,e.$validators.required=function(a,c){return!d.required||!e.$isEmpty(c)},d.$observe("required",function(){e.$validate()}))}}},wc=function(){return{restrict:"A",require:"?ngModel",link:function(a,c,d,e){if(e){var f,g=d.ngPattern||d.pattern;d.$observe("pattern",function(a){I(a)&&0<a.length&&(a=new RegExp("^"+a+"$"));if(a&&!a.test)throw z("ngPattern")("noregexp",g,a,va(c));f=a||u;e.$validate()});e.$validators.pattern=function(a){return e.$isEmpty(a)||G(f)||f.test(a)}}}}},zc=function(){return{restrict:"A",
|
||||||
|
require:"?ngModel",link:function(a,c,d,e){if(e){var f=-1;d.$observe("maxlength",function(a){a=$(a);f=isNaN(a)?-1:a;e.$validate()});e.$validators.maxlength=function(a,c){return 0>f||e.$isEmpty(a)||c.length<=f}}}}},yc=function(){return{restrict:"A",require:"?ngModel",link:function(a,c,d,e){if(e){var f=0;d.$observe("minlength",function(a){f=$(a)||0;e.$validate()});e.$validators.minlength=function(a,c){return e.$isEmpty(c)||c.length>=f}}}}},te=function(){return{restrict:"A",priority:100,require:"ngModel",
|
||||||
|
link:function(a,c,d,e){var f=c.attr(d.$attr.ngList)||", ",g="false"!==d.ngTrim,h=g?P(f):f;e.$parsers.push(function(a){if(!G(a)){var c=[];a&&r(a.split(h),function(a){a&&c.push(g?P(a):a)});return c}});e.$formatters.push(function(a){return D(a)?a.join(f):u});e.$isEmpty=function(a){return!a||!a.length}}}},Yf=/^(true|false|\d+)$/,ve=function(){return{restrict:"A",priority:100,compile:function(a,c){return Yf.test(c.ngValue)?function(a,c,f){f.$set("value",a.$eval(f.ngValue))}:function(a,c,f){a.$watch(f.ngValue,
|
||||||
|
function(a){f.$set("value",a)})}}}},we=function(){return{restrict:"A",controller:["$scope","$attrs",function(a,c){var d=this;this.$options=a.$eval(c.ngModelOptions);this.$options.updateOn!==u?(this.$options.updateOnDefault=!1,this.$options.updateOn=P(this.$options.updateOn.replace(Wf,function(){d.$options.updateOnDefault=!0;return" "}))):this.$options.updateOnDefault=!0}]}},Wd=["$compile",function(a){return{restrict:"AC",compile:function(c){a.$$addBindingClass(c);return function(c,e,f){a.$$addBindingInfo(e,
|
||||||
|
f.ngBind);e=e[0];c.$watch(f.ngBind,function(a){e.textContent=a===u?"":a})}}}}],Yd=["$interpolate","$compile",function(a,c){return{compile:function(d){c.$$addBindingClass(d);return function(d,f,g){d=a(f.attr(g.$attr.ngBindTemplate));c.$$addBindingInfo(f,d.expressions);f=f[0];g.$observe("ngBindTemplate",function(a){f.textContent=a===u?"":a})}}}}],Xd=["$sce","$parse","$compile",function(a,c,d){return{restrict:"A",compile:function(e,f){var g=c(f.ngBindHtml),h=c(f.ngBindHtml,function(a){return(a||"").toString()});
|
||||||
|
d.$$addBindingClass(e);return function(c,e,f){d.$$addBindingInfo(e,f.ngBindHtml);c.$watch(h,function(){e.html(a.getTrustedHtml(g(c))||"")})}}}}],Zd=ic("",!0),ae=ic("Odd",0),$d=ic("Even",1),be=Ia({compile:function(a,c){c.$set("ngCloak",u);a.removeClass("ng-cloak")}}),ce=[function(){return{restrict:"A",scope:!0,controller:"@",priority:500}}],Ac={},Zf={blur:!0,focus:!0};r("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "),
|
||||||
|
function(a){var c=wa("ng-"+a);Ac[c]=["$parse","$rootScope",function(d,e){return{restrict:"A",compile:function(f,g){var h=d(g[c],null,!0);return function(c,d){d.on(a,function(d){var f=function(){h(c,{$event:d})};Zf[a]&&e.$$phase?c.$evalAsync(f):c.$apply(f)})}}}}]});var fe=["$animate",function(a){return{multiElement:!0,transclude:"element",priority:600,terminal:!0,restrict:"A",$$tlb:!0,link:function(c,d,e,f,g){var h,k,l;c.$watch(e.ngIf,function(c){c?k||g(function(c,f){k=f;c[c.length++]=V.createComment(" end ngIf: "+
|
||||||
|
e.ngIf+" ");h={clone:c};a.enter(c,d.parent(),d)}):(l&&(l.remove(),l=null),k&&(k.$destroy(),k=null),h&&(l=qb(h.clone),a.leave(l).then(function(){l=null}),h=null))})}}}],ge=["$templateRequest","$anchorScroll","$animate","$sce",function(a,c,d,e){return{restrict:"ECA",priority:400,terminal:!0,transclude:"element",controller:ha.noop,compile:function(f,g){var h=g.ngInclude||g.src,k=g.onload||"",l=g.autoscroll;return function(f,g,s,r,q){var u=0,n,v,w,O=function(){v&&(v.remove(),v=null);n&&(n.$destroy(),
|
||||||
|
n=null);w&&(d.leave(w).then(function(){v=null}),v=w,w=null)};f.$watch(e.parseAsResourceUrl(h),function(e){var h=function(){!y(l)||l&&!f.$eval(l)||c()},s=++u;e?(a(e,!0).then(function(a){if(s===u){var c=f.$new();r.template=a;a=q(c,function(a){O();d.enter(a,null,g).then(h)});n=c;w=a;n.$emit("$includeContentLoaded",e);f.$eval(k)}},function(){s===u&&(O(),f.$emit("$includeContentError",e))}),f.$emit("$includeContentRequested",e)):(O(),r.template=null)})}}}}],xe=["$compile",function(a){return{restrict:"ECA",
|
||||||
|
priority:-400,require:"ngInclude",link:function(c,d,e,f){/SVG/.test(d[0].toString())?(d.empty(),a(Dc(f.template,V).childNodes)(c,function(a){d.append(a)},{futureParentElement:d})):(d.html(f.template),a(d.contents())(c))}}}],he=Ia({priority:450,compile:function(){return{pre:function(a,c,d){a.$eval(d.ngInit)}}}}),ie=Ia({terminal:!0,priority:1E3}),je=["$locale","$interpolate",function(a,c){var d=/{}/g,e=/^when(Minus)?(.+)$/;return{restrict:"EA",link:function(f,g,h){function k(a){g.text(a||"")}var l=
|
||||||
|
h.count,m=h.$attr.when&&g.attr(h.$attr.when),p=h.offset||0,s=f.$eval(m)||{},t={},m=c.startSymbol(),q=c.endSymbol(),u=m+l+"-"+p+q,n=ha.noop,v;r(h,function(a,c){var d=e.exec(c);d&&(d=(d[1]?"-":"")+R(d[2]),s[d]=g.attr(h.$attr[c]))});r(s,function(a,e){t[e]=c(a.replace(d,u))});f.$watch(l,function(c){c=parseFloat(c);var d=isNaN(c);d||c in s||(c=a.pluralCat(c-p));c===v||d&&isNaN(v)||(n(),n=f.$watch(t[c],k),v=c)})}}}],ke=["$parse","$animate",function(a,c){var d=z("ngRepeat"),e=function(a,c,d,e,l,m,p){a[d]=
|
||||||
|
e;l&&(a[l]=m);a.$index=c;a.$first=0===c;a.$last=c===p-1;a.$middle=!(a.$first||a.$last);a.$odd=!(a.$even=0===(c&1))};return{restrict:"A",multiElement:!0,transclude:"element",priority:1E3,terminal:!0,$$tlb:!0,compile:function(f,g){var h=g.ngRepeat,k=V.createComment(" end ngRepeat: "+h+" "),l=h.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);if(!l)throw d("iexp",h);var m=l[1],p=l[2],s=l[3],t=l[4],l=m.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
|
||||||
|
if(!l)throw d("iidexp",m);var q=l[3]||l[1],y=l[2];if(s&&(!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(s)||/^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent)$/.test(s)))throw d("badident",s);var n,v,w,z,E={$id:Ma};t?n=a(t):(w=function(a,c){return Ma(c)},z=function(a){return a});return function(a,f,g,l,m){n&&(v=function(c,d,e){y&&(E[y]=c);E[q]=d;E.$index=e;return n(a,E)});var t=ia();a.$watchCollection(p,function(g){var l,n,p=f[0],B,E=ia(),C,x,G,T,D,F,I;s&&(a[s]=g);if(Ra(g))D=g,n=v||
|
||||||
|
w;else{n=v||z;D=[];for(I in g)g.hasOwnProperty(I)&&"$"!=I.charAt(0)&&D.push(I);D.sort()}C=D.length;I=Array(C);for(l=0;l<C;l++)if(x=g===D?l:D[l],G=g[x],T=n(x,G,l),t[T])F=t[T],delete t[T],E[T]=F,I[l]=F;else{if(E[T])throw r(I,function(a){a&&a.scope&&(t[a.id]=a)}),d("dupes",h,T,G);I[l]={id:T,scope:u,clone:u};E[T]=!0}for(B in t){F=t[B];T=qb(F.clone);c.leave(T);if(T[0].parentNode)for(l=0,n=T.length;l<n;l++)T[l].$$NG_REMOVED=!0;F.scope.$destroy()}for(l=0;l<C;l++)if(x=g===D?l:D[l],G=g[x],F=I[l],F.scope){B=
|
||||||
|
p;do B=B.nextSibling;while(B&&B.$$NG_REMOVED);F.clone[0]!=B&&c.move(qb(F.clone),null,A(p));p=F.clone[F.clone.length-1];e(F.scope,l,q,G,y,x,C)}else m(function(a,d){F.scope=d;var f=k.cloneNode(!1);a[a.length++]=f;c.enter(a,null,A(p));p=f;F.clone=a;E[F.id]=F;e(F.scope,l,q,G,y,x,C)});t=E})}}}}],le=["$animate",function(a){return{restrict:"A",multiElement:!0,link:function(c,d,e){c.$watch(e.ngShow,function(c){a[c?"removeClass":"addClass"](d,"ng-hide",{tempClasses:"ng-hide-animate"})})}}}],ee=["$animate",
|
||||||
|
function(a){return{restrict:"A",multiElement:!0,link:function(c,d,e){c.$watch(e.ngHide,function(c){a[c?"addClass":"removeClass"](d,"ng-hide",{tempClasses:"ng-hide-animate"})})}}}],me=Ia(function(a,c,d){a.$watch(d.ngStyle,function(a,d){d&&a!==d&&r(d,function(a,d){c.css(d,"")});a&&c.css(a)},!0)}),ne=["$animate",function(a){return{restrict:"EA",require:"ngSwitch",controller:["$scope",function(){this.cases={}}],link:function(c,d,e,f){var g=[],h=[],k=[],l=[],m=function(a,c){return function(){a.splice(c,
|
||||||
|
1)}};c.$watch(e.ngSwitch||e.on,function(c){var d,e;d=0;for(e=k.length;d<e;++d)a.cancel(k[d]);d=k.length=0;for(e=l.length;d<e;++d){var q=qb(h[d].clone);l[d].$destroy();(k[d]=a.leave(q)).then(m(k,d))}h.length=0;l.length=0;(g=f.cases["!"+c]||f.cases["?"])&&r(g,function(c){c.transclude(function(d,e){l.push(e);var f=c.element;d[d.length++]=V.createComment(" end ngSwitchWhen: ");h.push({clone:d});a.enter(d,f.parent(),f)})})})}}}],oe=Ia({transclude:"element",priority:1200,require:"^ngSwitch",multiElement:!0,
|
||||||
|
link:function(a,c,d,e,f){e.cases["!"+d.ngSwitchWhen]=e.cases["!"+d.ngSwitchWhen]||[];e.cases["!"+d.ngSwitchWhen].push({transclude:f,element:c})}}),pe=Ia({transclude:"element",priority:1200,require:"^ngSwitch",multiElement:!0,link:function(a,c,d,e,f){e.cases["?"]=e.cases["?"]||[];e.cases["?"].push({transclude:f,element:c})}}),re=Ia({restrict:"EAC",link:function(a,c,d,e,f){if(!f)throw z("ngTransclude")("orphan",va(c));f(function(a){c.empty();c.append(a)})}}),Sd=["$templateCache",function(a){return{restrict:"E",
|
||||||
|
terminal:!0,compile:function(c,d){"text/ng-template"==d.type&&a.put(d.id,c[0].text)}}}],$f=z("ngOptions"),qe=ca({restrict:"A",terminal:!0}),Td=["$compile","$parse",function(a,c){var d=/^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/,e={$setViewValue:x};return{restrict:"E",require:["select","?ngModel"],controller:["$element","$scope","$attrs",function(a,
|
||||||
|
c,d){var k=this,l={},m=e,p;k.databound=d.ngModel;k.init=function(a,c,d){m=a;p=d};k.addOption=function(c,d){La(c,'"option value"');l[c]=!0;m.$viewValue==c&&(a.val(c),p.parent()&&p.remove());d&&d[0].hasAttribute("selected")&&(d[0].selected=!0)};k.removeOption=function(a){this.hasOption(a)&&(delete l[a],m.$viewValue==a&&this.renderUnknownOption(a))};k.renderUnknownOption=function(c){c="? "+Ma(c)+" ?";p.val(c);a.prepend(p);a.val(c);p.prop("selected",!0)};k.hasOption=function(a){return l.hasOwnProperty(a)};
|
||||||
|
c.$on("$destroy",function(){k.renderUnknownOption=x})}],link:function(e,g,h,k){function l(a,c,d,e){d.$render=function(){var a=d.$viewValue;e.hasOption(a)?(E.parent()&&E.remove(),c.val(a),""===a&&n.prop("selected",!0)):G(a)&&n?c.val(""):e.renderUnknownOption(a)};c.on("change",function(){a.$apply(function(){E.parent()&&E.remove();d.$setViewValue(c.val())})})}function m(a,c,d){var e;d.$render=function(){var a=new cb(d.$viewValue);r(c.find("option"),function(c){c.selected=y(a.get(c.value))})};a.$watch(function(){pa(e,
|
||||||
|
d.$viewValue)||(e=ua(d.$viewValue),d.$render())});c.on("change",function(){a.$apply(function(){var a=[];r(c.find("option"),function(c){c.selected&&a.push(c.value)});d.$setViewValue(a)})})}function p(e,f,g){function h(a,c,d){U[x]=d;G&&(U[G]=c);return a(e,U)}function k(a){var c;if(t)if(K&&D(a)){c=new cb([]);for(var d=0;d<a.length;d++)c.put(h(K,null,a[d]),!0)}else c=new cb(a);else K&&(a=h(K,null,a));return function(d,e){var f;f=K?K:C?C:H;return t?y(c.remove(h(f,d,e))):a===h(f,d,e)}}function l(){v||(e.$$postDigest(n),
|
||||||
|
v=!0)}function m(a,c,d){a[c]=a[c]||0;a[c]+=d?1:-1}function n(){v=!1;var a={"":[]},c=[""],d,l,p,q,u;p=g.$viewValue;q=M(e)||[];var C=G?Object.keys(q).sort():q,x,A,H,D,Q={};u=k(p);var P=!1,V,X;S={};for(D=0;H=C.length,D<H;D++){x=D;if(G&&(x=C[D],"$"===x.charAt(0)))continue;A=q[x];d=h(I,x,A)||"";(l=a[d])||(l=a[d]=[],c.push(d));d=u(x,A);P=P||d;A=h(E,x,A);A=y(A)?A:"";X=K?K(e,U):G?C[D]:D;K&&(S[X]=x);l.push({id:X,label:A,selected:d})}t||(z||null===p?a[""].unshift({id:"",label:"",selected:!P}):P||a[""].unshift({id:"?",
|
||||||
|
label:"",selected:!0}));x=0;for(C=c.length;x<C;x++){d=c[x];l=a[d];R.length<=x?(p={element:F.clone().attr("label",d),label:l.label},q=[p],R.push(q),f.append(p.element)):(q=R[x],p=q[0],p.label!=d&&p.element.attr("label",p.label=d));P=null;D=0;for(H=l.length;D<H;D++)d=l[D],(u=q[D+1])?(P=u.element,u.label!==d.label&&(m(Q,u.label,!1),m(Q,d.label,!0),P.text(u.label=d.label),P.prop("label",u.label)),u.id!==d.id&&P.val(u.id=d.id),P[0].selected!==d.selected&&(P.prop("selected",u.selected=d.selected),Ha&&P.prop("selected",
|
||||||
|
u.selected))):(""===d.id&&z?V=z:(V=w.clone()).val(d.id).prop("selected",d.selected).attr("selected",d.selected).prop("label",d.label).text(d.label),q.push(u={element:V,label:d.label,id:d.id,selected:d.selected}),m(Q,d.label,!0),P?P.after(V):p.element.append(V),P=V);for(D++;q.length>D;)d=q.pop(),m(Q,d.label,!1),d.element.remove();r(Q,function(a,c){0<a?s.addOption(c):0>a&&s.removeOption(c)})}for(;R.length>x;)R.pop()[0].element.remove()}var p;if(!(p=q.match(d)))throw $f("iexp",q,va(f));var E=c(p[2]||
|
||||||
|
p[1]),x=p[4]||p[6],A=/ as /.test(p[0])&&p[1],C=A?c(A):null,G=p[5],I=c(p[3]||""),H=c(p[2]?p[1]:x),M=c(p[7]),K=p[8]?c(p[8]):null,S={},R=[[{element:f,label:""}]],U={};z&&(a(z)(e),z.removeClass("ng-scope"),z.remove());f.empty();f.on("change",function(){e.$apply(function(){var a=M(e)||[],c;if(t)c=[],r(f.val(),function(d){d=K?S[d]:d;c.push("?"===d?u:""===d?null:h(C?C:H,d,a[d]))});else{var d=K?S[f.val()]:f.val();c="?"===d?u:""===d?null:h(C?C:H,d,a[d])}g.$setViewValue(c);n()})});g.$render=n;e.$watchCollection(M,
|
||||||
|
l);e.$watchCollection(function(){var a=M(e),c;if(a&&D(a)){c=Array(a.length);for(var d=0,f=a.length;d<f;d++)c[d]=h(E,d,a[d])}else if(a)for(d in c={},a)a.hasOwnProperty(d)&&(c[d]=h(E,d,a[d]));return c},l);t&&e.$watchCollection(function(){return g.$modelValue},l)}if(k[1]){var s=k[0];k=k[1];var t=h.multiple,q=h.ngOptions,z=!1,n,v=!1,w=A(V.createElement("option")),F=A(V.createElement("optgroup")),E=w.clone();h=0;for(var x=g.children(),C=x.length;h<C;h++)if(""===x[h].value){n=z=x.eq(h);break}s.init(k,z,
|
||||||
|
E);t&&(k.$isEmpty=function(a){return!a||0===a.length});q?p(e,g,k):t?m(e,g,k):l(e,g,k,s)}}}}],Vd=["$interpolate",function(a){var c={addOption:x,removeOption:x};return{restrict:"E",priority:100,compile:function(d,e){if(G(e.value)){var f=a(d.text(),!0);f||e.$set("value",d.text())}return function(a,d,e){var l=d.parent(),m=l.data("$selectController")||l.parent().data("$selectController");m&&m.databound||(m=c);f?a.$watch(f,function(a,c){e.$set("value",a);c!==a&&m.removeOption(c);m.addOption(a,d)}):m.addOption(e.value,
|
||||||
|
d);d.on("$destroy",function(){m.removeOption(e.value)})}}}}],Ud=ca({restrict:"E",terminal:!1});U.angular.bootstrap?console.log("WARNING: Tried to load angular more than once."):(Kd(),Md(ha),A(V).ready(function(){Gd(V,rc)}))})(window,document);!window.angular.$$csp()&&window.angular.element(document).find("head").prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}</style>');
|
||||||
|
//# sourceMappingURL=angular.min.js.map
|
783
sources/js/linuxDash.js
Normal file
783
sources/js/linuxDash.js
Normal file
|
@ -0,0 +1,783 @@
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
angular.module('linuxDash', ['ngRoute']);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Routes for different tabs on UI
|
||||||
|
*/
|
||||||
|
angular.module('linuxDash').config(['$routeProvider',
|
||||||
|
function($routeProvider) {
|
||||||
|
|
||||||
|
$routeProvider.
|
||||||
|
when('/loading', {
|
||||||
|
templateUrl: 'templates/app/loading.html',
|
||||||
|
controller: function appLoadController ($scope, $location, $rootScope) {
|
||||||
|
|
||||||
|
var loadUrl = localStorage.getItem('currentTab') || 'system-status';
|
||||||
|
|
||||||
|
var loadLinuxDash = function () {
|
||||||
|
$location.path(loadUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
$rootScope.$on('start-linux-dash', loadLinuxDash);
|
||||||
|
|
||||||
|
},
|
||||||
|
}).
|
||||||
|
when('/system-status', {
|
||||||
|
templateUrl: 'templates/sections/system-status.html',
|
||||||
|
}).
|
||||||
|
when('/basic-info', {
|
||||||
|
templateUrl: 'templates/sections/basic-info.html',
|
||||||
|
}).
|
||||||
|
when('/network', {
|
||||||
|
templateUrl: 'templates/sections/network.html',
|
||||||
|
}).
|
||||||
|
when('/accounts', {
|
||||||
|
templateUrl: 'templates/sections/accounts.html',
|
||||||
|
}).
|
||||||
|
when('/apps', {
|
||||||
|
templateUrl: 'templates/sections/applications.html',
|
||||||
|
}).
|
||||||
|
otherwise({
|
||||||
|
redirectTo: '/loading'
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service which gets data from server
|
||||||
|
* via HTTP or Websocket (if supported)
|
||||||
|
*/
|
||||||
|
angular.module('linuxDash').service('server', ['$http', '$rootScope', '$location', function($http, $rootScope, $location) {
|
||||||
|
|
||||||
|
var websocket = {
|
||||||
|
connection: null,
|
||||||
|
onMessageEventHandlers: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description:
|
||||||
|
* Establish a websocket connection with server
|
||||||
|
*
|
||||||
|
* @return Null
|
||||||
|
*/
|
||||||
|
var establishWebsocketConnection = function() {
|
||||||
|
|
||||||
|
var websocketUrl = 'ws://' + window.location.hostname + ':' + window.location.port;
|
||||||
|
|
||||||
|
if (websocket.connection === null) {
|
||||||
|
|
||||||
|
websocket.connection = new WebSocket(websocketUrl, 'linux-dash');
|
||||||
|
|
||||||
|
websocket.connection.onopen = function() {
|
||||||
|
$rootScope.$broadcast("start-linux-dash", {});
|
||||||
|
$rootScope.$apply();
|
||||||
|
console.info('Websocket connection is open');
|
||||||
|
};
|
||||||
|
|
||||||
|
websocket.connection.onmessage = function(event) {
|
||||||
|
|
||||||
|
var response = JSON.parse(event.data);
|
||||||
|
var moduleName = response.moduleName;
|
||||||
|
var moduleData = JSON.parse(response.output);
|
||||||
|
|
||||||
|
if (!!websocket.onMessageEventHandlers[moduleName]) {
|
||||||
|
websocket.onMessageEventHandlers[moduleName](moduleData);
|
||||||
|
} else {
|
||||||
|
console.info("Websocket could not find module", moduleName, "in:", websocket.onMessageEventHandlers);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
websocket.connection.onclose = function() {
|
||||||
|
websocket.connection = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description:
|
||||||
|
* Check if websockets are supported
|
||||||
|
* If so, call establishWebsocketConnection()
|
||||||
|
*
|
||||||
|
* @return Null
|
||||||
|
*/
|
||||||
|
this.checkIfWebsocketsAreSupported = function() {
|
||||||
|
|
||||||
|
var websocketSupport = {
|
||||||
|
browser: null,
|
||||||
|
server: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
// does browser support websockets?
|
||||||
|
if (window.WebSocket) {
|
||||||
|
|
||||||
|
websocketSupport.browser = true;
|
||||||
|
|
||||||
|
// does backend support websockets?
|
||||||
|
$http.get("/websocket").then(function(response) {
|
||||||
|
|
||||||
|
// if websocket_support property exists and is trurthy
|
||||||
|
// websocketSupport.server will equal true.
|
||||||
|
websocketSupport.server = !!response.data["websocket_support"];
|
||||||
|
|
||||||
|
}).catch(function websocketNotSupportedByServer() {
|
||||||
|
|
||||||
|
websocketSupport.server = false;
|
||||||
|
$rootScope.$broadcast("start-linux-dash", {});
|
||||||
|
|
||||||
|
}).then(function finalDecisionOnWebsocket() {
|
||||||
|
|
||||||
|
if (websocketSupport.browser && websocketSupport.server) {
|
||||||
|
|
||||||
|
establishWebsocketConnection();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// rootScope event not propogating from here.
|
||||||
|
// instead, we manually route to url
|
||||||
|
$location.path('/system-status');
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles requests from modules for data from server
|
||||||
|
*
|
||||||
|
* @param {String} moduleName
|
||||||
|
* @param {Function} callback
|
||||||
|
* @return {[ Null || callback(server response) ]}
|
||||||
|
*/
|
||||||
|
this.get = function(moduleName, callback) {
|
||||||
|
|
||||||
|
// if we have a websocket connection
|
||||||
|
if (websocket.connection) {
|
||||||
|
|
||||||
|
// and the connection is ready
|
||||||
|
if (websocket.connection.readyState === 1) {
|
||||||
|
|
||||||
|
// set the callback as the event handler
|
||||||
|
// for server response.
|
||||||
|
//
|
||||||
|
// Callback instance needs to be overwritten
|
||||||
|
// each time for this to work. Not sure why.
|
||||||
|
websocket.onMessageEventHandlers[moduleName] = callback;
|
||||||
|
|
||||||
|
//
|
||||||
|
websocket.connection.send(moduleName);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
console.log("Websocket not ready yet.", moduleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// otherwise
|
||||||
|
else {
|
||||||
|
|
||||||
|
var moduleAddress = 'server/?module=' + moduleName;
|
||||||
|
|
||||||
|
return $http.get(moduleAddress).then(function(response) {
|
||||||
|
return callback(response.data);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to run websocket support check.
|
||||||
|
*/
|
||||||
|
angular.module('linuxDash').run(function(server, $location, $rootScope) {
|
||||||
|
|
||||||
|
server.checkIfWebsocketsAreSupported();
|
||||||
|
|
||||||
|
var currentRoute = $location.path();
|
||||||
|
var currentTab = (currentRoute === '/loading')? 'system-status': currentRoute;
|
||||||
|
localStorage.setItem('currentTab', currentTab);
|
||||||
|
|
||||||
|
$location.path('/loading');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sidebar for SPA
|
||||||
|
*/
|
||||||
|
angular.module('linuxDash').directive('navBar', function($location) {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
templateUrl: 'templates/app/navbar.html',
|
||||||
|
link: function(scope) {
|
||||||
|
scope.items = [
|
||||||
|
'system-status',
|
||||||
|
'basic-info',
|
||||||
|
'network',
|
||||||
|
'accounts',
|
||||||
|
'apps'
|
||||||
|
];
|
||||||
|
|
||||||
|
scope.getNavItemName = function(url) {
|
||||||
|
return url.replace('-', ' ');
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.isActive = function(route) {
|
||||||
|
return '/' + route === $location.path();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
////////////////// UI Element Directives ////////////////// //
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows loader
|
||||||
|
*/
|
||||||
|
angular.module('linuxDash').directive('loader', function() {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {
|
||||||
|
width: '@'
|
||||||
|
},
|
||||||
|
template: '<div class="spinner">' +
|
||||||
|
' <div class="rect1"></div>' +
|
||||||
|
' <div class="rect2"></div>' +
|
||||||
|
' <div class="rect3"></div>' +
|
||||||
|
' <div class="rect4"></div>' +
|
||||||
|
' <div class="rect5"></div>' +
|
||||||
|
'</div>'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Top Bar for widget
|
||||||
|
*/
|
||||||
|
angular.module('linuxDash').directive('topBar', function() {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {
|
||||||
|
heading: '=',
|
||||||
|
refresh: '&',
|
||||||
|
lastUpdated: '=',
|
||||||
|
info: '=',
|
||||||
|
},
|
||||||
|
templateUrl: 'templates/app/ui-elements/top-bar.html',
|
||||||
|
link: function(scope, element, attrs) {
|
||||||
|
var $refreshBtn = element.find('refresh-btn').eq(0);
|
||||||
|
|
||||||
|
if (typeof attrs.noRefreshBtn !== 'undefined') {
|
||||||
|
$refreshBtn.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows refresh button and calls
|
||||||
|
* provided expression on-click
|
||||||
|
*/
|
||||||
|
angular.module('linuxDash').directive('refreshBtn', function() {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {
|
||||||
|
refresh: '&'
|
||||||
|
},
|
||||||
|
template: '<button ng-click="refresh()">↺</button>'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message shown when no data is found from server
|
||||||
|
*/
|
||||||
|
angular.module('linuxDash').directive('noData', function() {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
template: 'No Data'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays last updated timestamp for widget
|
||||||
|
*/
|
||||||
|
angular.module('linuxDash').directive('lastUpdate', function() {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {
|
||||||
|
timestamp: '='
|
||||||
|
},
|
||||||
|
templateUrl: 'templates/app/ui-elements/last-update.html'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
////////////////// Plugin Directives //////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches and displays table data
|
||||||
|
*/
|
||||||
|
angular.module('linuxDash').directive('tableData', ['server', '$rootScope', function(server, $rootScope) {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {
|
||||||
|
heading: '@',
|
||||||
|
info: '@',
|
||||||
|
moduleName: '@'
|
||||||
|
},
|
||||||
|
templateUrl: 'templates/app/table-data-plugin.html',
|
||||||
|
link: function(scope, element) {
|
||||||
|
|
||||||
|
scope.sortByColumn = null;
|
||||||
|
scope.sortReverse = null;
|
||||||
|
|
||||||
|
// set the column to sort by
|
||||||
|
scope.setSortColumn = function(column) {
|
||||||
|
|
||||||
|
// if the column is already being sorted
|
||||||
|
// reverse the order
|
||||||
|
if (column === scope.sortByColumn) {
|
||||||
|
scope.sortReverse = !scope.sortReverse;
|
||||||
|
} else {
|
||||||
|
scope.sortByColumn = column;
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.sortTableRows();
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.sortTableRows = function() {
|
||||||
|
scope.tableRows.sort(function(currentRow, nextRow) {
|
||||||
|
|
||||||
|
var sortResult = 0;
|
||||||
|
|
||||||
|
if (currentRow[scope.sortByColumn] < nextRow[scope.sortByColumn]) {
|
||||||
|
sortResult = -1;
|
||||||
|
} else if (currentRow[scope.sortByColumn] === nextRow[scope.sortByColumn]) {
|
||||||
|
sortResult = 0;
|
||||||
|
} else {
|
||||||
|
sortResult = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scope.sortReverse) {
|
||||||
|
sortResult = -1 * sortResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sortResult;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.getData = function() {
|
||||||
|
delete scope.tableRows;
|
||||||
|
|
||||||
|
server.get(scope.moduleName, function(serverResponseData) {
|
||||||
|
|
||||||
|
if (serverResponseData.length > 0) {
|
||||||
|
scope.tableHeaders = Object.keys(serverResponseData[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.tableRows = serverResponseData;
|
||||||
|
|
||||||
|
if (scope.sortByColumn) {
|
||||||
|
scope.sortTableRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.lastGet = new Date().getTime();
|
||||||
|
|
||||||
|
if (serverResponseData.length < 1) {
|
||||||
|
scope.emptyResult = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!scope.$$phase && !$rootScope.$$phase) scope.$digest();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.getData();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches and displays table data
|
||||||
|
*/
|
||||||
|
angular.module('linuxDash').directive('keyValueList', ['server', '$rootScope', function(server, $rootScope) {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {
|
||||||
|
heading: '@',
|
||||||
|
info: '@',
|
||||||
|
moduleName: '@',
|
||||||
|
},
|
||||||
|
templateUrl: 'templates/app/key-value-list-plugin.html',
|
||||||
|
link: function(scope, element) {
|
||||||
|
|
||||||
|
scope.getData = function() {
|
||||||
|
delete scope.tableRows;
|
||||||
|
|
||||||
|
server.get(scope.moduleName, function(serverResponseData) {
|
||||||
|
scope.tableRows = serverResponseData;
|
||||||
|
scope.lastGet = new Date().getTime();
|
||||||
|
|
||||||
|
if (Object.keys(serverResponseData).length === 0) {
|
||||||
|
scope.emptyResult = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!scope.$$phase && !$rootScope.$$phase) scope.$digest();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.getData();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches and displays data as line chart at a certain refresh rate
|
||||||
|
*/
|
||||||
|
angular.module('linuxDash').directive('lineChartPlugin', ['$interval', '$compile', 'server', function($interval, $compile, server) {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {
|
||||||
|
heading: '@',
|
||||||
|
moduleName: '@',
|
||||||
|
refreshRate: '=',
|
||||||
|
maxValue: '=',
|
||||||
|
minValue: '=',
|
||||||
|
getDisplayValue: '=',
|
||||||
|
metrics: '=',
|
||||||
|
color: '@'
|
||||||
|
},
|
||||||
|
templateUrl: 'templates/app/line-chart-plugin.html',
|
||||||
|
link: function(scope, element) {
|
||||||
|
|
||||||
|
if (!scope.color) scope.color = '0, 255, 0';
|
||||||
|
|
||||||
|
var series;
|
||||||
|
|
||||||
|
// smoothieJS - Create new chart
|
||||||
|
var chart = new SmoothieChart({
|
||||||
|
borderVisible: false,
|
||||||
|
sharpLines: true,
|
||||||
|
grid: {
|
||||||
|
fillStyle: '#ffffff',
|
||||||
|
strokeStyle: 'rgba(232,230,230,0.93)',
|
||||||
|
sharpLines: true,
|
||||||
|
millisPerLine: 3000,
|
||||||
|
borderVisible: false
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
fontSize: 11,
|
||||||
|
precision: 0,
|
||||||
|
fillStyle: '#0f0e0e'
|
||||||
|
},
|
||||||
|
maxValue: parseInt(scope.maxValue),
|
||||||
|
minValue: parseInt(scope.minValue),
|
||||||
|
horizontalLines: [{
|
||||||
|
value: 5,
|
||||||
|
color: '#eff',
|
||||||
|
lineWidth: 1
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
// smoothieJS - set up canvas element for chart
|
||||||
|
canvas = element.find('canvas')[0];
|
||||||
|
series = new TimeSeries();
|
||||||
|
|
||||||
|
chart.addTimeSeries(series, {
|
||||||
|
strokeStyle: 'rgba(' + scope.color + ', 1)',
|
||||||
|
fillStyle: 'rgba(' + scope.color + ', 0.2)',
|
||||||
|
lineWidth: 2
|
||||||
|
});
|
||||||
|
|
||||||
|
chart.streamTo(canvas, 1000);
|
||||||
|
|
||||||
|
var dataCallInProgress = false;
|
||||||
|
|
||||||
|
// update data on chart
|
||||||
|
scope.getData = function() {
|
||||||
|
|
||||||
|
if (dataCallInProgress) return;
|
||||||
|
|
||||||
|
dataCallInProgress = true;
|
||||||
|
|
||||||
|
server.get(scope.moduleName, function(serverResponseData) {
|
||||||
|
|
||||||
|
dataCallInProgress = false;
|
||||||
|
scope.lastGet = new Date().getTime();
|
||||||
|
|
||||||
|
// change graph colour depending on usage
|
||||||
|
if (scope.maxValue / 4 * 3 < scope.getDisplayValue(serverResponseData)) {
|
||||||
|
chart.seriesSet[0].options.strokeStyle = 'rgba(255, 89, 0, 1)';
|
||||||
|
chart.seriesSet[0].options.fillStyle = 'rgba(255, 89, 0, 0.2)';
|
||||||
|
} else if (scope.maxValue / 3 < scope.getDisplayValue(serverResponseData)) {
|
||||||
|
chart.seriesSet[0].options.strokeStyle = 'rgba(255, 238, 0, 1)';
|
||||||
|
chart.seriesSet[0].options.fillStyle = 'rgba(255, 238, 0, 0.2)';
|
||||||
|
} else {
|
||||||
|
chart.seriesSet[0].options.strokeStyle = 'rgba(' + scope.color + ', 1)';
|
||||||
|
chart.seriesSet[0].options.fillStyle = 'rgba(' + scope.color + ', 0.2)';
|
||||||
|
}
|
||||||
|
|
||||||
|
// update chart with this response
|
||||||
|
series.append(scope.lastGet, scope.getDisplayValue(serverResponseData));
|
||||||
|
|
||||||
|
// update the metrics for this chart
|
||||||
|
scope.metrics.forEach(function(metricObj) {
|
||||||
|
metricObj.data = metricObj.generate(serverResponseData);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// set the directive-provided interval
|
||||||
|
// at which to run the chart update
|
||||||
|
var intervalRef = $interval(scope.getData, scope.refreshRate);
|
||||||
|
var removeInterval = function() {
|
||||||
|
$interval.cancel(intervalRef);
|
||||||
|
};
|
||||||
|
|
||||||
|
element.on("$destroy", removeInterval);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches and displays data as line chart at a certain refresh rate
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
angular.module('linuxDash').directive('multiLineChartPlugin', ['$interval', '$compile', 'server', function($interval, $compile, server) {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {
|
||||||
|
heading: '@',
|
||||||
|
moduleName: '@',
|
||||||
|
refreshRate: '=',
|
||||||
|
getDisplayValue: '=',
|
||||||
|
units: '=',
|
||||||
|
delay: '='
|
||||||
|
},
|
||||||
|
templateUrl: 'templates/app/multi-line-chart-plugin.html',
|
||||||
|
link: function(scope, element) {
|
||||||
|
|
||||||
|
// smoothieJS - Create new chart
|
||||||
|
var chart = new SmoothieChart({
|
||||||
|
borderVisible: false,
|
||||||
|
sharpLines: true,
|
||||||
|
grid: {
|
||||||
|
fillStyle: '#ffffff',
|
||||||
|
strokeStyle: 'rgba(232,230,230,0.93)',
|
||||||
|
sharpLines: true,
|
||||||
|
borderVisible: false
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
fontSize: 12,
|
||||||
|
precision: 0,
|
||||||
|
fillStyle: '#0f0e0e'
|
||||||
|
},
|
||||||
|
maxValue: 100,
|
||||||
|
minValue: 0,
|
||||||
|
horizontalLines: [{
|
||||||
|
value: 1,
|
||||||
|
color: '#ecc',
|
||||||
|
lineWidth: 1
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
var seriesOptions = [{
|
||||||
|
strokeStyle: 'rgba(255, 0, 0, 1)',
|
||||||
|
lineWidth: 2
|
||||||
|
}, {
|
||||||
|
strokeStyle: 'rgba(0, 255, 0, 1)',
|
||||||
|
lineWidth: 2
|
||||||
|
}, {
|
||||||
|
strokeStyle: 'rgba(0, 0, 255, 1)',
|
||||||
|
lineWidth: 2
|
||||||
|
}, {
|
||||||
|
strokeStyle: 'rgba(255, 255, 0, 1)',
|
||||||
|
lineWidth: 1
|
||||||
|
}];
|
||||||
|
|
||||||
|
// smoothieJS - set up canvas element for chart
|
||||||
|
var canvas = element.find('canvas')[0];
|
||||||
|
scope.seriesArray = [];
|
||||||
|
scope.metricsArray = [];
|
||||||
|
|
||||||
|
// get the data once to set up # of lines on chart
|
||||||
|
server.get(scope.moduleName, function(serverResponseData) {
|
||||||
|
|
||||||
|
var numberOfLines = Object.keys(serverResponseData).length;
|
||||||
|
|
||||||
|
for (var x = 0; x < numberOfLines; x++) {
|
||||||
|
|
||||||
|
var keyForThisLine = Object.keys(serverResponseData)[x];
|
||||||
|
|
||||||
|
scope.seriesArray[x] = new TimeSeries();
|
||||||
|
chart.addTimeSeries(scope.seriesArray[x], seriesOptions[x]);
|
||||||
|
scope.metricsArray[x] = {
|
||||||
|
name: keyForThisLine,
|
||||||
|
color: seriesOptions[x].strokeStyle,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
var delay = 1000;
|
||||||
|
|
||||||
|
if (angular.isDefined(scope.delay))
|
||||||
|
delay = scope.delay;
|
||||||
|
|
||||||
|
chart.streamTo(canvas, delay);
|
||||||
|
|
||||||
|
var dataCallInProgress = false;
|
||||||
|
|
||||||
|
// update data on chart
|
||||||
|
scope.getData = function() {
|
||||||
|
|
||||||
|
if (dataCallInProgress) return;
|
||||||
|
|
||||||
|
if (!scope.seriesArray.length) return;
|
||||||
|
|
||||||
|
dataCallInProgress = true;
|
||||||
|
|
||||||
|
server.get(scope.moduleName, function(serverResponseData) {
|
||||||
|
|
||||||
|
dataCallInProgress = false;
|
||||||
|
scope.lastGet = new Date().getTime();
|
||||||
|
var keyCount = 0;
|
||||||
|
var maxAvg = 100;
|
||||||
|
|
||||||
|
// update chart with current response
|
||||||
|
for (var key in serverResponseData) {
|
||||||
|
scope.seriesArray[keyCount].append(scope.lastGet, serverResponseData[key]);
|
||||||
|
keyCount++;
|
||||||
|
maxAvg = Math.max(maxAvg, serverResponseData[key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the metrics for this chart
|
||||||
|
scope.metricsArray.forEach(function(metricObj) {
|
||||||
|
metricObj.data = serverResponseData[metricObj.name].toString() + ' ' + scope.units;
|
||||||
|
});
|
||||||
|
|
||||||
|
// round up the average and set the maximum scale
|
||||||
|
var len = parseInt(Math.log(maxAvg) / Math.log(10));
|
||||||
|
var div = Math.pow(10, len);
|
||||||
|
chart.options.maxValue = Math.ceil(maxAvg / div) * div;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
var refreshRate = (angular.isDefined(scope.refreshRate)) ? scope.refreshRate : 1000;
|
||||||
|
var intervalRef = $interval(scope.getData, refreshRate);
|
||||||
|
var removeInterval = function() {
|
||||||
|
$interval.cancel(intervalRef);
|
||||||
|
};
|
||||||
|
|
||||||
|
element.on("$destroy", removeInterval);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base plugin structure
|
||||||
|
*/
|
||||||
|
angular.module('linuxDash').directive('plugin', function() {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
transclude: true,
|
||||||
|
templateUrl: 'templates/app/base-plugin.html'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Progress bar element
|
||||||
|
*/
|
||||||
|
angular.module('linuxDash').directive('progressBarPlugin', function() {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {
|
||||||
|
width: '@',
|
||||||
|
moduleName: '@',
|
||||||
|
name: '@',
|
||||||
|
value: '@',
|
||||||
|
max: '@'
|
||||||
|
},
|
||||||
|
templateUrl: 'templates/app/progress-bar-plugin.html'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Theme switcher
|
||||||
|
*/
|
||||||
|
angular.module('linuxDash').directive('themeSwitcher', ['$location', function($location) {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
templateUrl: 'templates/app/theme-switcher.html',
|
||||||
|
link: function(scope) {
|
||||||
|
|
||||||
|
// alternate themes available
|
||||||
|
scope.themes = [{
|
||||||
|
name: 'winter',
|
||||||
|
}, {
|
||||||
|
name: 'summer',
|
||||||
|
}, {
|
||||||
|
name: 'spring',
|
||||||
|
}, {
|
||||||
|
name: 'fall',
|
||||||
|
}, {
|
||||||
|
name: 'old',
|
||||||
|
}, ];
|
||||||
|
|
||||||
|
scope.themeSwitcherOpen = false;
|
||||||
|
|
||||||
|
scope.switchTheme = function(theme) {
|
||||||
|
|
||||||
|
if (theme.selected) {
|
||||||
|
scope.setDefaultTheme();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.removeExistingThemes();
|
||||||
|
theme.selected = true;
|
||||||
|
document.getElementsByTagName('html')[0].className = theme.name;
|
||||||
|
localStorage.setItem('theme', theme.name);
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.toggleThemeSwitcher = function() {
|
||||||
|
scope.themeSwitcherOpen = !scope.themeSwitcherOpen;
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.removeExistingThemes = function() {
|
||||||
|
scope.themes.forEach(function(item) {
|
||||||
|
item.selected = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.setDefaultTheme = function() {
|
||||||
|
scope.removeExistingThemes();
|
||||||
|
document.getElementsByTagName('html')[0].className = '';
|
||||||
|
localStorage.setItem('theme', null);
|
||||||
|
};
|
||||||
|
|
||||||
|
// on load, check if theme was set in localStorage
|
||||||
|
if (localStorage.getItem('theme')) {
|
||||||
|
|
||||||
|
scope.themes.forEach(function(theme) {
|
||||||
|
|
||||||
|
if (theme.name === localStorage.getItem('theme')) {
|
||||||
|
scope.switchTheme(theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
||||||
|
}());
|
284
sources/js/modules.js
Normal file
284
sources/js/modules.js
Normal file
|
@ -0,0 +1,284 @@
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
////////////////// Module Directives /////////////////// //
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
angular.module('linuxDash').directive('diskSpace', ['server', function(server) {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {},
|
||||||
|
templateUrl: 'templates/modules/disk-space.html',
|
||||||
|
link: function(scope) {
|
||||||
|
|
||||||
|
scope.heading = "Disk Partitions";
|
||||||
|
|
||||||
|
scope.getData = function() {
|
||||||
|
server.get('disk_partitions', function(serverResponseData) {
|
||||||
|
scope.diskSpaceData = serverResponseData;
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.lastGet = new Date().getTime();
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.getData();
|
||||||
|
|
||||||
|
scope.getKB = function(stringSize) {
|
||||||
|
var lastChar = stringSize.slice(-1),
|
||||||
|
size = parseInt(stringSize);
|
||||||
|
|
||||||
|
switch (lastChar) {
|
||||||
|
case 'M':
|
||||||
|
return size * Math.pow(1024, 1);
|
||||||
|
case 'G':
|
||||||
|
return size * Math.pow(1024, 2);
|
||||||
|
case 'T':
|
||||||
|
return size * Math.pow(1024, 3);
|
||||||
|
case 'P':
|
||||||
|
return size * Math.pow(1024, 4);
|
||||||
|
case 'E':
|
||||||
|
return size * Math.pow(1024, 5);
|
||||||
|
case 'Z':
|
||||||
|
return size * Math.pow(1024, 6);
|
||||||
|
case 'Y':
|
||||||
|
return size * Math.pow(1024, 7);
|
||||||
|
default:
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
||||||
|
angular.module('linuxDash').directive('ramChart', ['server', function(server) {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {},
|
||||||
|
templateUrl: 'templates/modules/ram-chart.html',
|
||||||
|
link: function(scope) {
|
||||||
|
|
||||||
|
// get max ram available on machine before we
|
||||||
|
// can start charting
|
||||||
|
server.get('current_ram', function(resp) {
|
||||||
|
scope.maxRam = resp.total;
|
||||||
|
scope.minRam = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.ramToDisplay = function(serverResponseData) {
|
||||||
|
return serverResponseData.used;
|
||||||
|
};
|
||||||
|
|
||||||
|
var humanizeRam = function (ramInMB) {
|
||||||
|
var ram = {
|
||||||
|
value: parseInt(ramInMB, 10),
|
||||||
|
unit: 'MB',
|
||||||
|
};
|
||||||
|
|
||||||
|
// if ram > 1,000 MB, use GB
|
||||||
|
if (ram.value > 1000) {
|
||||||
|
ram = {
|
||||||
|
value: (ramInMB/1024).toFixed(2),
|
||||||
|
unit: 'GB',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return ram.value + ' ' + ram.unit;
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.ramMetrics = [{
|
||||||
|
name: 'Used',
|
||||||
|
generate: function(serverResponseData) {
|
||||||
|
var ratio = serverResponseData.used / serverResponseData.total;
|
||||||
|
var percentage = parseInt(ratio * 100);
|
||||||
|
|
||||||
|
var usedRam = humanizeRam(serverResponseData.used);
|
||||||
|
return usedRam + ' (' + percentage.toString() + '%)';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Free',
|
||||||
|
generate: function(serverResponseData) {
|
||||||
|
|
||||||
|
var freeRam = humanizeRam(serverResponseData.free);
|
||||||
|
var totalRam = humanizeRam(serverResponseData.total);
|
||||||
|
return freeRam + ' of ' + totalRam;
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
||||||
|
angular.module('linuxDash').directive('cpuAvgLoadChart', ['server', function(server) {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {},
|
||||||
|
templateUrl: 'templates/modules/cpu-load.html',
|
||||||
|
link: function(scope) {
|
||||||
|
scope.units = '%';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
||||||
|
angular.module('linuxDash').directive('cpuUtilizationChart', ['server', function(server) {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {},
|
||||||
|
templateUrl: 'templates/modules/cpu-utilization-chart.html',
|
||||||
|
link: function(scope) {
|
||||||
|
scope.min = 0;
|
||||||
|
scope.max = 100;
|
||||||
|
|
||||||
|
scope.displayValue = function(serverResponseData) {
|
||||||
|
return serverResponseData;
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.utilMetrics = [{
|
||||||
|
name: 'Usage',
|
||||||
|
generate: function(serverResponseData) {
|
||||||
|
return serverResponseData + ' %';
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
||||||
|
angular.module('linuxDash').directive('uploadTransferRateChart', ['server', function(server) {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {},
|
||||||
|
templateUrl: 'templates/modules/upload-transfer-rate.html',
|
||||||
|
link: function(scope) {
|
||||||
|
scope.delay = 2000;
|
||||||
|
scope.units = 'KB/s';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
||||||
|
angular.module('linuxDash').directive('downloadTransferRateChart', ['server', function(server) {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {},
|
||||||
|
templateUrl: 'templates/modules/download-transfer-rate.html',
|
||||||
|
link: function(scope) {
|
||||||
|
scope.delay = 2000;
|
||||||
|
scope.units = 'KB/s';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
/////////////// Table Data Modules //////////////////// //
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
var simpleTableModules = [
|
||||||
|
{
|
||||||
|
name: 'machineInfo',
|
||||||
|
template: '<key-value-list heading="General Info." module-name="general_info" info="System Information"></key-value-list>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ipAddresses',
|
||||||
|
template: '<table-data heading="IP Addresses" module-name="ip_addresses" info="IPs assigned to this server"></table-data>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ramIntensiveProcesses',
|
||||||
|
template: '<table-data heading="RAM Intensive Processes" module-name="ram_intensive_processes" info="Processes which are using most RAM."></table-data>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'cpuIntensiveProcesses',
|
||||||
|
template: '<table-data heading="CPU Intensive Processes" module-name="cpu_intensive_processes" info="Processes which are using most CPU."></table-data>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'networkConnections',
|
||||||
|
template: '<table-data heading="Network Connections" module-name="network_connections"></table-data>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'serverAccounts',
|
||||||
|
template: '<table-data heading="Accounts" module-name="user_accounts" info="User accounts on this server."></table-data>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'loggedInAccounts',
|
||||||
|
template: '<table-data heading="Logged In Accounts" module-name="logged_in_users" info="Users currently logged in."></table-data>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'recentLogins',
|
||||||
|
template: '<table-data heading="Recent Logins" module-name="recent_account_logins" info="Recent user sessions."></table-data>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'arpCacheTable',
|
||||||
|
template: '<table-data heading="ARP Cache Table" module-name="arp_cache"></table-data>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'commonApplications',
|
||||||
|
template: '<table-data heading="Common Applications" module-name="common_applications" info="List of commonly installed applications."></table-data>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'pingSpeeds',
|
||||||
|
template: '<table-data heading="Ping Speeds" module-name="ping" info="Ping speed in milliseconds."></table-data>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'bandwidth',
|
||||||
|
template: '<table-data heading="Bandwidth" module-name="bandwidth"></table-data>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'swapUsage',
|
||||||
|
template: '<table-data heading="Swap Usage" module-name="swap"></table-data>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'internetSpeed',
|
||||||
|
template: '<key-value-list heading="Internet Speed" module-name="internet_speed" info="Internet connection speed of server."></key-value-list>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'memcached',
|
||||||
|
template: '<key-value-list heading="Memcached" module-name="memcached"></key-value-list>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'redis',
|
||||||
|
template: '<key-value-list heading="Redis" module-name="redis"></key-value-list>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'memoryInfo',
|
||||||
|
template: '<key-value-list heading="Memory Info" module-name="memory_info" info="/proc/meminfo read-out."></key-value-list>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'cpuInfo',
|
||||||
|
template: '<key-value-list heading="CPU Info" module-name="cpu_info" info="/usr/bin/lscpu read-out."></key-value-list>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ioStats',
|
||||||
|
template: '<table-data heading="IO Stats" module-name="io_stats" info="/proc/diskstats read-out."></table-data>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'scheduledCrons',
|
||||||
|
template: '<table-data heading="Scheduled Cron Jobs" module-name="scheduled_crons" info="Crons for all users on the server."></table-data>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'cronHistory',
|
||||||
|
template: '<table-data heading="Cron Job History" module-name="cron_history" info="Crons which have run recently."></table-data>'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
simpleTableModules.forEach(function(module, key) {
|
||||||
|
|
||||||
|
angular.module('linuxDash').directive(module.name, ['server', function(server) {
|
||||||
|
|
||||||
|
var moduleDirective = {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (module.templateUrl) {
|
||||||
|
moduleDirective['templateUrl'] = 'templates/modules/' + module.templateUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
if (module.template) {
|
||||||
|
moduleDirective['template'] = module.template;
|
||||||
|
}
|
||||||
|
|
||||||
|
return moduleDirective;
|
||||||
|
}]);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}());
|
1
sources/js/smoothie.min.js
vendored
Normal file
1
sources/js/smoothie.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
30
sources/package.json
Normal file
30
sources/package.json
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"name": "linux-dash",
|
||||||
|
"version": "1.2.0",
|
||||||
|
"description": "A simple, low overhead web dashboard for linux.",
|
||||||
|
"main": "server/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/afaqurk/linux-dash.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"linux",
|
||||||
|
"gnu",
|
||||||
|
"dashboard",
|
||||||
|
"monitor",
|
||||||
|
"server"
|
||||||
|
],
|
||||||
|
"author": "Afaq Tariq",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/afaqurk/linux-dash/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/afaqurk/linux-dash",
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.11.1",
|
||||||
|
"websocket": "^1.0.22"
|
||||||
|
}
|
||||||
|
}
|
45
sources/python-server.py
Executable file
45
sources/python-server.py
Executable file
|
@ -0,0 +1,45 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
|
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer, test as _test
|
||||||
|
import subprocess
|
||||||
|
from SocketServer import ThreadingMixIn
|
||||||
|
|
||||||
|
modulesSubPath = '/server/modules/shell_files/'
|
||||||
|
serverPath = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
|
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class MainHandler(BaseHTTPRequestHandler):
|
||||||
|
def do_GET(self):
|
||||||
|
try:
|
||||||
|
data = ''
|
||||||
|
contentType = 'text/html'
|
||||||
|
if self.path.startswith("/server/"):
|
||||||
|
module = self.path.split('=')[1]
|
||||||
|
output = subprocess.Popen(
|
||||||
|
serverPath + modulesSubPath + module + '.sh',
|
||||||
|
shell = True,
|
||||||
|
stdout = subprocess.PIPE)
|
||||||
|
data = output.communicate()[0]
|
||||||
|
else:
|
||||||
|
if self.path == '/':
|
||||||
|
self.path = 'index.html'
|
||||||
|
f = open(os.path.dirname(os.path.realpath(__file__)) + os.sep + self.path)
|
||||||
|
data = f.read()
|
||||||
|
if self.path.startswith('/css/'):
|
||||||
|
contentType = 'text/css'
|
||||||
|
f.close()
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header('Content-type', contentType)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(data)
|
||||||
|
|
||||||
|
except IOError:
|
||||||
|
self.send_error(404, 'File Not Found: %s' % self.path)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
server = ThreadedHTTPServer(('localhost', 8081), MainHandler)
|
||||||
|
print 'Starting server, use <Ctrl-C> to stop'
|
||||||
|
server.serve_forever()
|
53
sources/server/index.go
Normal file
53
sources/server/index.go
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
listenAddress = flag.String("listen", "0.0.0.0:80", "Where the server listens for connections. [interface]:port")
|
||||||
|
staticPath = flag.String("static", "../", "Location of static files.")
|
||||||
|
scriptPath = flag.String("scripts", "./modules/shell_files", "Location of shell scripts used to gather stats.")
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
flag.Parse()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
http.Handle("/", http.FileServer(http.Dir(*staticPath)))
|
||||||
|
http.HandleFunc("/server/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
module := r.URL.Query().Get("module")
|
||||||
|
script := filepath.Join(*scriptPath, module+".sh")
|
||||||
|
if module == "" {
|
||||||
|
http.Error(w, "No module specified, or requested module doesn't exist.", 406)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the command
|
||||||
|
cmd := exec.Command(script)
|
||||||
|
var output bytes.Buffer
|
||||||
|
cmd.Stdout = &output
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error executing '%s': %s\n\tScript output: %s\n", script, err.Error(), output.String())
|
||||||
|
http.Error(w, "Unable to execute module.", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write(output.Bytes())
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println("Starting http server at:", *listenAddress)
|
||||||
|
err := http.ListenAndServe(*listenAddress, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error starting http server:", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
107
sources/server/index.js
Normal file
107
sources/server/index.js
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
var express = require('express');
|
||||||
|
var app = require('express')();
|
||||||
|
var server = require('http').Server(app);
|
||||||
|
var path = require('path');
|
||||||
|
var spawn = require('child_process').spawn;
|
||||||
|
var fs = require('fs');
|
||||||
|
var ws = require('websocket').server;
|
||||||
|
|
||||||
|
server.listen(80);
|
||||||
|
console.log('Linux Dash Server Started!');
|
||||||
|
|
||||||
|
app.use(express.static(path.resolve(__dirname + '/../')));
|
||||||
|
|
||||||
|
app.get('/', function (req, res) {
|
||||||
|
res.sendFile(path.resolve(__dirname + '/../index.html'));
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/websocket', function (req, res) {
|
||||||
|
|
||||||
|
res.send({
|
||||||
|
websocket_support: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
wsServer = new ws({
|
||||||
|
httpServer: server
|
||||||
|
});
|
||||||
|
|
||||||
|
function getShellFilePath(moduleName) {
|
||||||
|
return __dirname + '/modules/shell_files/' + moduleName + '.sh';
|
||||||
|
}
|
||||||
|
|
||||||
|
function shellPathAndModuleNameAreValid(shellFilePath, moduleName) {
|
||||||
|
|
||||||
|
var moduleInvalidName = moduleName.indexOf('.') > -1;
|
||||||
|
var moduleNameEmpty = !moduleName;
|
||||||
|
var moduleNotFound = !fs.existsSync(shellFilePath);
|
||||||
|
var isValid = true;
|
||||||
|
|
||||||
|
if (moduleInvalidName || moduleNameEmpty || moduleNotFound) {
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
wsServer.on('request', function(request) {
|
||||||
|
|
||||||
|
var wsClient = request.accept('linux-dash', request.origin);
|
||||||
|
|
||||||
|
wsClient.on('message', function(wsReq) {
|
||||||
|
|
||||||
|
var moduleName = wsReq.utf8Data;
|
||||||
|
var shellFile = getShellFilePath(moduleName);
|
||||||
|
|
||||||
|
if (!shellPathAndModuleNameAreValid(shellFile, moduleName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var command = spawn(shellFile, [ wsReq.color || '' ]);
|
||||||
|
var output = [];
|
||||||
|
|
||||||
|
command.stdout.on('data', function(chunk) {
|
||||||
|
output.push(chunk);
|
||||||
|
});
|
||||||
|
|
||||||
|
command.on('close', function(code) {
|
||||||
|
|
||||||
|
if (code === 0) {
|
||||||
|
|
||||||
|
var wsResponse = {
|
||||||
|
moduleName: moduleName,
|
||||||
|
output: output.toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
wsClient.sendUTF(JSON.stringify(wsResponse));
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/server/', function (req, res) {
|
||||||
|
|
||||||
|
var shellFile = getShellFilePath(req.query.module);
|
||||||
|
|
||||||
|
if (!shellPathAndModuleNameAreValid(shellFile, req.query.module)) {
|
||||||
|
res.sendStatus(406);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var command = spawn(shellFile, [ req.query.color || '' ]);
|
||||||
|
var output = [];
|
||||||
|
|
||||||
|
command.stdout.on('data', function(chunk) {
|
||||||
|
output.push(chunk);
|
||||||
|
});
|
||||||
|
|
||||||
|
command.on('close', function(code) {
|
||||||
|
if (code === 0) res.send(output.toString());
|
||||||
|
else res.sendStatus(500);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
8
sources/server/index.php
Normal file
8
sources/server/index.php
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
header("Cache-Control: no-store, no-cache, must-revalidate");
|
||||||
|
header("Pragma: no-cache");
|
||||||
|
|
||||||
|
$modules_dir = dirname(__FILE__) . '/modules/shell_files/';
|
||||||
|
$module = escapeshellcmd($_GET['module']);
|
||||||
|
|
||||||
|
echo shell_exec( $modules_dir . $module . '.sh' );
|
3
sources/server/modules/config/ping_hosts
Normal file
3
sources/server/modules/config/ping_hosts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
google.com
|
||||||
|
yahoo.com
|
||||||
|
twitter.com
|
694
sources/server/modules/python_files/speedtest_cli.py
Executable file
694
sources/server/modules/python_files/speedtest_cli.py
Executable file
|
@ -0,0 +1,694 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2012-2014 Matt Martz
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
__version__ = '0.3.1'
|
||||||
|
|
||||||
|
# Some global variables we use
|
||||||
|
source = None
|
||||||
|
shutdown_event = None
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import math
|
||||||
|
import signal
|
||||||
|
import socket
|
||||||
|
import timeit
|
||||||
|
import threading
|
||||||
|
|
||||||
|
# Used for bound_interface
|
||||||
|
socket_socket = socket.socket
|
||||||
|
|
||||||
|
try:
|
||||||
|
import xml.etree.cElementTree as ET
|
||||||
|
except ImportError:
|
||||||
|
try:
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
except ImportError:
|
||||||
|
from xml.dom import minidom as DOM
|
||||||
|
ET = None
|
||||||
|
|
||||||
|
# Begin import game to handle Python 2 and Python 3
|
||||||
|
try:
|
||||||
|
from urllib2 import urlopen, Request, HTTPError, URLError
|
||||||
|
except ImportError:
|
||||||
|
from urllib.request import urlopen, Request, HTTPError, URLError
|
||||||
|
|
||||||
|
try:
|
||||||
|
from httplib import HTTPConnection, HTTPSConnection
|
||||||
|
except ImportError:
|
||||||
|
from http.client import HTTPConnection, HTTPSConnection
|
||||||
|
|
||||||
|
try:
|
||||||
|
from Queue import Queue
|
||||||
|
except ImportError:
|
||||||
|
from queue import Queue
|
||||||
|
|
||||||
|
try:
|
||||||
|
from urlparse import urlparse
|
||||||
|
except ImportError:
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
try:
|
||||||
|
from urlparse import parse_qs
|
||||||
|
except ImportError:
|
||||||
|
try:
|
||||||
|
from urllib.parse import parse_qs
|
||||||
|
except ImportError:
|
||||||
|
from cgi import parse_qs
|
||||||
|
|
||||||
|
try:
|
||||||
|
from hashlib import md5
|
||||||
|
except ImportError:
|
||||||
|
from md5 import md5
|
||||||
|
|
||||||
|
try:
|
||||||
|
from argparse import ArgumentParser as ArgParser
|
||||||
|
except ImportError:
|
||||||
|
from optparse import OptionParser as ArgParser
|
||||||
|
|
||||||
|
try:
|
||||||
|
import builtins
|
||||||
|
except ImportError:
|
||||||
|
def print_(*args, **kwargs):
|
||||||
|
"""The new-style print function taken from
|
||||||
|
https://pypi.python.org/pypi/six/
|
||||||
|
|
||||||
|
"""
|
||||||
|
fp = kwargs.pop("file", sys.stdout)
|
||||||
|
if fp is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
def write(data):
|
||||||
|
if not isinstance(data, basestring):
|
||||||
|
data = str(data)
|
||||||
|
fp.write(data)
|
||||||
|
|
||||||
|
want_unicode = False
|
||||||
|
sep = kwargs.pop("sep", None)
|
||||||
|
if sep is not None:
|
||||||
|
if isinstance(sep, unicode):
|
||||||
|
want_unicode = True
|
||||||
|
elif not isinstance(sep, str):
|
||||||
|
raise TypeError("sep must be None or a string")
|
||||||
|
end = kwargs.pop("end", None)
|
||||||
|
if end is not None:
|
||||||
|
if isinstance(end, unicode):
|
||||||
|
want_unicode = True
|
||||||
|
elif not isinstance(end, str):
|
||||||
|
raise TypeError("end must be None or a string")
|
||||||
|
if kwargs:
|
||||||
|
raise TypeError("invalid keyword arguments to print()")
|
||||||
|
if not want_unicode:
|
||||||
|
for arg in args:
|
||||||
|
if isinstance(arg, unicode):
|
||||||
|
want_unicode = True
|
||||||
|
break
|
||||||
|
if want_unicode:
|
||||||
|
newline = unicode("\n")
|
||||||
|
space = unicode(" ")
|
||||||
|
else:
|
||||||
|
newline = "\n"
|
||||||
|
space = " "
|
||||||
|
if sep is None:
|
||||||
|
sep = space
|
||||||
|
if end is None:
|
||||||
|
end = newline
|
||||||
|
for i, arg in enumerate(args):
|
||||||
|
if i:
|
||||||
|
write(sep)
|
||||||
|
write(arg)
|
||||||
|
write(end)
|
||||||
|
else:
|
||||||
|
print_ = getattr(builtins, 'print')
|
||||||
|
del builtins
|
||||||
|
|
||||||
|
|
||||||
|
def bound_socket(*args, **kwargs):
|
||||||
|
"""Bind socket to a specified source IP address"""
|
||||||
|
|
||||||
|
global source
|
||||||
|
sock = socket_socket(*args, **kwargs)
|
||||||
|
sock.bind((source, 0))
|
||||||
|
return sock
|
||||||
|
|
||||||
|
|
||||||
|
def distance(origin, destination):
|
||||||
|
"""Determine distance between 2 sets of [lat,lon] in km"""
|
||||||
|
|
||||||
|
lat1, lon1 = origin
|
||||||
|
lat2, lon2 = destination
|
||||||
|
radius = 6371 # km
|
||||||
|
|
||||||
|
dlat = math.radians(lat2 - lat1)
|
||||||
|
dlon = math.radians(lon2 - lon1)
|
||||||
|
a = (math.sin(dlat / 2) * math.sin(dlat / 2) + math.cos(math.radians(lat1))
|
||||||
|
* math.cos(math.radians(lat2)) * math.sin(dlon / 2)
|
||||||
|
* math.sin(dlon / 2))
|
||||||
|
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
|
||||||
|
d = radius * c
|
||||||
|
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
class FileGetter(threading.Thread):
|
||||||
|
"""Thread class for retrieving a URL"""
|
||||||
|
|
||||||
|
def __init__(self, url, start):
|
||||||
|
self.url = url
|
||||||
|
self.result = None
|
||||||
|
self.starttime = start
|
||||||
|
threading.Thread.__init__(self)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.result = [0]
|
||||||
|
try:
|
||||||
|
if (timeit.default_timer() - self.starttime) <= 10:
|
||||||
|
f = urlopen(self.url)
|
||||||
|
while 1 and not shutdown_event.isSet():
|
||||||
|
self.result.append(len(f.read(10240)))
|
||||||
|
if self.result[-1] == 0:
|
||||||
|
break
|
||||||
|
f.close()
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def downloadSpeed(files, quiet=False):
|
||||||
|
"""Function to launch FileGetter threads and calculate download speeds"""
|
||||||
|
|
||||||
|
start = timeit.default_timer()
|
||||||
|
|
||||||
|
def producer(q, files):
|
||||||
|
for file in files:
|
||||||
|
thread = FileGetter(file, start)
|
||||||
|
thread.start()
|
||||||
|
q.put(thread, True)
|
||||||
|
if not quiet and not shutdown_event.isSet():
|
||||||
|
sys.stdout.write('.')
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
finished = []
|
||||||
|
|
||||||
|
def consumer(q, total_files):
|
||||||
|
while len(finished) < total_files:
|
||||||
|
thread = q.get(True)
|
||||||
|
while thread.isAlive():
|
||||||
|
thread.join(timeout=0.1)
|
||||||
|
finished.append(sum(thread.result))
|
||||||
|
del thread
|
||||||
|
|
||||||
|
q = Queue(6)
|
||||||
|
prod_thread = threading.Thread(target=producer, args=(q, files))
|
||||||
|
cons_thread = threading.Thread(target=consumer, args=(q, len(files)))
|
||||||
|
start = timeit.default_timer()
|
||||||
|
prod_thread.start()
|
||||||
|
cons_thread.start()
|
||||||
|
while prod_thread.isAlive():
|
||||||
|
prod_thread.join(timeout=0.1)
|
||||||
|
while cons_thread.isAlive():
|
||||||
|
cons_thread.join(timeout=0.1)
|
||||||
|
return (sum(finished) / (timeit.default_timer() - start))
|
||||||
|
|
||||||
|
|
||||||
|
class FilePutter(threading.Thread):
|
||||||
|
"""Thread class for putting a URL"""
|
||||||
|
|
||||||
|
def __init__(self, url, start, size):
|
||||||
|
self.url = url
|
||||||
|
chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||||
|
data = chars * (int(round(int(size) / 36.0)))
|
||||||
|
self.data = ('content1=%s' % data[0:int(size) - 9]).encode()
|
||||||
|
del data
|
||||||
|
self.result = None
|
||||||
|
self.starttime = start
|
||||||
|
threading.Thread.__init__(self)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
try:
|
||||||
|
if ((timeit.default_timer() - self.starttime) <= 10 and
|
||||||
|
not shutdown_event.isSet()):
|
||||||
|
f = urlopen(self.url, self.data)
|
||||||
|
f.read(11)
|
||||||
|
f.close()
|
||||||
|
self.result = len(self.data)
|
||||||
|
else:
|
||||||
|
self.result = 0
|
||||||
|
except IOError:
|
||||||
|
self.result = 0
|
||||||
|
|
||||||
|
|
||||||
|
def uploadSpeed(url, sizes, quiet=False):
|
||||||
|
"""Function to launch FilePutter threads and calculate upload speeds"""
|
||||||
|
|
||||||
|
start = timeit.default_timer()
|
||||||
|
|
||||||
|
def producer(q, sizes):
|
||||||
|
for size in sizes:
|
||||||
|
thread = FilePutter(url, start, size)
|
||||||
|
thread.start()
|
||||||
|
q.put(thread, True)
|
||||||
|
if not quiet and not shutdown_event.isSet():
|
||||||
|
sys.stdout.write('.')
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
finished = []
|
||||||
|
|
||||||
|
def consumer(q, total_sizes):
|
||||||
|
while len(finished) < total_sizes:
|
||||||
|
thread = q.get(True)
|
||||||
|
while thread.isAlive():
|
||||||
|
thread.join(timeout=0.1)
|
||||||
|
finished.append(thread.result)
|
||||||
|
del thread
|
||||||
|
|
||||||
|
q = Queue(6)
|
||||||
|
prod_thread = threading.Thread(target=producer, args=(q, sizes))
|
||||||
|
cons_thread = threading.Thread(target=consumer, args=(q, len(sizes)))
|
||||||
|
start = timeit.default_timer()
|
||||||
|
prod_thread.start()
|
||||||
|
cons_thread.start()
|
||||||
|
while prod_thread.isAlive():
|
||||||
|
prod_thread.join(timeout=0.1)
|
||||||
|
while cons_thread.isAlive():
|
||||||
|
cons_thread.join(timeout=0.1)
|
||||||
|
return (sum(finished) / (timeit.default_timer() - start))
|
||||||
|
|
||||||
|
|
||||||
|
def getAttributesByTagName(dom, tagName):
|
||||||
|
"""Retrieve an attribute from an XML document and return it in a
|
||||||
|
consistent format
|
||||||
|
|
||||||
|
Only used with xml.dom.minidom, which is likely only to be used
|
||||||
|
with python versions older than 2.5
|
||||||
|
"""
|
||||||
|
elem = dom.getElementsByTagName(tagName)[0]
|
||||||
|
return dict(list(elem.attributes.items()))
|
||||||
|
|
||||||
|
|
||||||
|
def getConfig():
|
||||||
|
"""Download the speedtest.net configuration and return only the data
|
||||||
|
we are interested in
|
||||||
|
"""
|
||||||
|
|
||||||
|
uh = urlopen('http://www.speedtest.net/speedtest-config.php')
|
||||||
|
configxml = []
|
||||||
|
while 1:
|
||||||
|
configxml.append(uh.read(10240))
|
||||||
|
if len(configxml[-1]) == 0:
|
||||||
|
break
|
||||||
|
if int(uh.code) != 200:
|
||||||
|
return None
|
||||||
|
uh.close()
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
root = ET.fromstring(''.encode().join(configxml))
|
||||||
|
config = {
|
||||||
|
'client': root.find('client').attrib,
|
||||||
|
'times': root.find('times').attrib,
|
||||||
|
'download': root.find('download').attrib,
|
||||||
|
'upload': root.find('upload').attrib}
|
||||||
|
except AttributeError:
|
||||||
|
root = DOM.parseString(''.join(configxml))
|
||||||
|
config = {
|
||||||
|
'client': getAttributesByTagName(root, 'client'),
|
||||||
|
'times': getAttributesByTagName(root, 'times'),
|
||||||
|
'download': getAttributesByTagName(root, 'download'),
|
||||||
|
'upload': getAttributesByTagName(root, 'upload')}
|
||||||
|
except SyntaxError:
|
||||||
|
print_('Failed to parse speedtest.net configuration')
|
||||||
|
sys.exit(1)
|
||||||
|
del root
|
||||||
|
del configxml
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
def closestServers(client, all=False):
|
||||||
|
"""Determine the 5 closest speedtest.net servers based on geographic
|
||||||
|
distance
|
||||||
|
"""
|
||||||
|
|
||||||
|
uh = urlopen('http://www.speedtest.net/speedtest-servers-static.php')
|
||||||
|
serversxml = []
|
||||||
|
while 1:
|
||||||
|
serversxml.append(uh.read(10240))
|
||||||
|
if len(serversxml[-1]) == 0:
|
||||||
|
break
|
||||||
|
if int(uh.code) != 200:
|
||||||
|
return None
|
||||||
|
uh.close()
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
root = ET.fromstring(''.encode().join(serversxml))
|
||||||
|
elements = root.getiterator('server')
|
||||||
|
except AttributeError:
|
||||||
|
root = DOM.parseString(''.join(serversxml))
|
||||||
|
elements = root.getElementsByTagName('server')
|
||||||
|
except SyntaxError:
|
||||||
|
print_('Failed to parse list of speedtest.net servers')
|
||||||
|
sys.exit(1)
|
||||||
|
servers = {}
|
||||||
|
for server in elements:
|
||||||
|
try:
|
||||||
|
attrib = server.attrib
|
||||||
|
except AttributeError:
|
||||||
|
attrib = dict(list(server.attributes.items()))
|
||||||
|
d = distance([float(client['lat']), float(client['lon'])],
|
||||||
|
[float(attrib.get('lat')), float(attrib.get('lon'))])
|
||||||
|
attrib['d'] = d
|
||||||
|
if d not in servers:
|
||||||
|
servers[d] = [attrib]
|
||||||
|
else:
|
||||||
|
servers[d].append(attrib)
|
||||||
|
del root
|
||||||
|
del serversxml
|
||||||
|
del elements
|
||||||
|
|
||||||
|
closest = []
|
||||||
|
for d in sorted(servers.keys()):
|
||||||
|
for s in servers[d]:
|
||||||
|
closest.append(s)
|
||||||
|
if len(closest) == 5 and not all:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
|
||||||
|
del servers
|
||||||
|
return closest
|
||||||
|
|
||||||
|
|
||||||
|
def getBestServer(servers):
|
||||||
|
"""Perform a speedtest.net latency request to determine which
|
||||||
|
speedtest.net server has the lowest latency
|
||||||
|
"""
|
||||||
|
|
||||||
|
results = {}
|
||||||
|
for server in servers:
|
||||||
|
cum = []
|
||||||
|
url = '%s/latency.txt' % os.path.dirname(server['url'])
|
||||||
|
urlparts = urlparse(url)
|
||||||
|
for i in range(0, 3):
|
||||||
|
try:
|
||||||
|
if urlparts[0] == 'https':
|
||||||
|
h = HTTPSConnection(urlparts[1])
|
||||||
|
else:
|
||||||
|
h = HTTPConnection(urlparts[1])
|
||||||
|
start = timeit.default_timer()
|
||||||
|
h.request("GET", urlparts[2])
|
||||||
|
r = h.getresponse()
|
||||||
|
total = (timeit.default_timer() - start)
|
||||||
|
except (HTTPError, URLError, socket.error):
|
||||||
|
cum.append(3600)
|
||||||
|
continue
|
||||||
|
text = r.read(9)
|
||||||
|
if int(r.status) == 200 and text == 'test=test'.encode():
|
||||||
|
cum.append(total)
|
||||||
|
else:
|
||||||
|
cum.append(3600)
|
||||||
|
h.close()
|
||||||
|
avg = round((sum(cum) / 6) * 1000, 3)
|
||||||
|
results[avg] = server
|
||||||
|
fastest = sorted(results.keys())[0]
|
||||||
|
best = results[fastest]
|
||||||
|
best['latency'] = fastest
|
||||||
|
|
||||||
|
return best
|
||||||
|
|
||||||
|
|
||||||
|
def ctrl_c(signum, frame):
|
||||||
|
"""Catch Ctrl-C key sequence and set a shutdown_event for our threaded
|
||||||
|
operations
|
||||||
|
"""
|
||||||
|
|
||||||
|
global shutdown_event
|
||||||
|
shutdown_event.set()
|
||||||
|
raise SystemExit('\nCancelling...')
|
||||||
|
|
||||||
|
|
||||||
|
def version():
|
||||||
|
"""Print the version"""
|
||||||
|
|
||||||
|
raise SystemExit(__version__)
|
||||||
|
|
||||||
|
|
||||||
|
def speedtest():
|
||||||
|
"""Run the full speedtest.net test"""
|
||||||
|
|
||||||
|
global shutdown_event, source
|
||||||
|
shutdown_event = threading.Event()
|
||||||
|
|
||||||
|
signal.signal(signal.SIGINT, ctrl_c)
|
||||||
|
|
||||||
|
description = (
|
||||||
|
'Command line interface for testing internet bandwidth using '
|
||||||
|
'speedtest.net.\n'
|
||||||
|
'------------------------------------------------------------'
|
||||||
|
'--------------\n'
|
||||||
|
'https://github.com/sivel/speedtest-cli')
|
||||||
|
|
||||||
|
parser = ArgParser(description=description)
|
||||||
|
# Give optparse.OptionParser an `add_argument` method for
|
||||||
|
# compatibility with argparse.ArgumentParser
|
||||||
|
try:
|
||||||
|
parser.add_argument = parser.add_option
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
parser.add_argument('--bytes', dest='units', action='store_const',
|
||||||
|
const=('bytes', 1), default=('bits', 8),
|
||||||
|
help='Display values in bytes instead of bits. Does '
|
||||||
|
'not affect the image generated by --share')
|
||||||
|
parser.add_argument('--share', action='store_true',
|
||||||
|
help='Generate and provide a URL to the speedtest.net '
|
||||||
|
'share results image')
|
||||||
|
parser.add_argument('--simple', action='store_true',
|
||||||
|
help='Suppress verbose output, only show basic '
|
||||||
|
'information')
|
||||||
|
parser.add_argument('--list', action='store_true',
|
||||||
|
help='Display a list of speedtest.net servers '
|
||||||
|
'sorted by distance')
|
||||||
|
parser.add_argument('--server', help='Specify a server ID to test against')
|
||||||
|
parser.add_argument('--mini', help='URL of the Speedtest Mini server')
|
||||||
|
parser.add_argument('--source', help='Source IP address to bind to')
|
||||||
|
parser.add_argument('--version', action='store_true',
|
||||||
|
help='Show the version number and exit')
|
||||||
|
|
||||||
|
options = parser.parse_args()
|
||||||
|
if isinstance(options, tuple):
|
||||||
|
args = options[0]
|
||||||
|
else:
|
||||||
|
args = options
|
||||||
|
del options
|
||||||
|
|
||||||
|
# Print the version and exit
|
||||||
|
if args.version:
|
||||||
|
version()
|
||||||
|
|
||||||
|
# If specified bind to a specific IP address
|
||||||
|
if args.source:
|
||||||
|
source = args.source
|
||||||
|
socket.socket = bound_socket
|
||||||
|
|
||||||
|
if not args.simple:
|
||||||
|
print_('Retrieving speedtest.net configuration...')
|
||||||
|
try:
|
||||||
|
config = getConfig()
|
||||||
|
except URLError:
|
||||||
|
print_('Cannot retrieve speedtest configuration')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if not args.simple:
|
||||||
|
print_('Retrieving speedtest.net server list...')
|
||||||
|
if args.list or args.server:
|
||||||
|
servers = closestServers(config['client'], True)
|
||||||
|
if args.list:
|
||||||
|
serverList = []
|
||||||
|
for server in servers:
|
||||||
|
line = ('%(id)4s) %(sponsor)s (%(name)s, %(country)s) '
|
||||||
|
'[%(d)0.2f km]' % server)
|
||||||
|
serverList.append(line)
|
||||||
|
# Python 2.7 and newer seem to be ok with the resultant encoding
|
||||||
|
# from parsing the XML, but older versions have some issues.
|
||||||
|
# This block should detect whether we need to encode or not
|
||||||
|
try:
|
||||||
|
unicode()
|
||||||
|
print_('\n'.join(serverList).encode('utf-8', 'ignore'))
|
||||||
|
except NameError:
|
||||||
|
print_('\n'.join(serverList))
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
servers = closestServers(config['client'])
|
||||||
|
|
||||||
|
if not args.simple:
|
||||||
|
print_('Testing from %(isp)s (%(ip)s)...' % config['client'])
|
||||||
|
|
||||||
|
if args.server:
|
||||||
|
try:
|
||||||
|
best = getBestServer(filter(lambda x: x['id'] == args.server,
|
||||||
|
servers))
|
||||||
|
except IndexError:
|
||||||
|
print_('Invalid server ID')
|
||||||
|
sys.exit(1)
|
||||||
|
elif args.mini:
|
||||||
|
name, ext = os.path.splitext(args.mini)
|
||||||
|
if ext:
|
||||||
|
url = os.path.dirname(args.mini)
|
||||||
|
else:
|
||||||
|
url = args.mini
|
||||||
|
urlparts = urlparse(url)
|
||||||
|
try:
|
||||||
|
f = urlopen(args.mini)
|
||||||
|
except:
|
||||||
|
print_('Invalid Speedtest Mini URL')
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
text = f.read()
|
||||||
|
f.close()
|
||||||
|
extension = re.findall('upload_extension: "([^"]+)"', text.decode())
|
||||||
|
if not extension:
|
||||||
|
for ext in ['php', 'asp', 'aspx', 'jsp']:
|
||||||
|
try:
|
||||||
|
f = urlopen('%s/speedtest/upload.%s' % (args.mini, ext))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
data = f.read().strip()
|
||||||
|
if (f.code == 200 and
|
||||||
|
len(data.splitlines()) == 1 and
|
||||||
|
re.match('size=[0-9]', data)):
|
||||||
|
extension = [ext]
|
||||||
|
break
|
||||||
|
if not urlparts or not extension:
|
||||||
|
print_('Please provide the full URL of your Speedtest Mini server')
|
||||||
|
sys.exit(1)
|
||||||
|
servers = [{
|
||||||
|
'sponsor': 'Speedtest Mini',
|
||||||
|
'name': urlparts[1],
|
||||||
|
'd': 0,
|
||||||
|
'url': '%s/speedtest/upload.%s' % (url.rstrip('/'), extension[0]),
|
||||||
|
'latency': 0,
|
||||||
|
'id': 0
|
||||||
|
}]
|
||||||
|
try:
|
||||||
|
best = getBestServer(servers)
|
||||||
|
except:
|
||||||
|
best = servers[0]
|
||||||
|
else:
|
||||||
|
if not args.simple:
|
||||||
|
print_('Selecting best server based on latency...')
|
||||||
|
best = getBestServer(servers)
|
||||||
|
|
||||||
|
if not args.simple:
|
||||||
|
# Python 2.7 and newer seem to be ok with the resultant encoding
|
||||||
|
# from parsing the XML, but older versions have some issues.
|
||||||
|
# This block should detect whether we need to encode or not
|
||||||
|
try:
|
||||||
|
unicode()
|
||||||
|
print_(('Hosted by %(sponsor)s (%(name)s) [%(d)0.2f km]: '
|
||||||
|
'%(latency)s ms' % best).encode('utf-8', 'ignore'))
|
||||||
|
except NameError:
|
||||||
|
print_('Hosted by %(sponsor)s (%(name)s) [%(d)0.2f km]: '
|
||||||
|
'%(latency)s ms' % best)
|
||||||
|
else:
|
||||||
|
print_('Ping: %(latency)s ms' % best)
|
||||||
|
|
||||||
|
sizes = [350, 500, 750, 1000, 1500, 2000, 2500, 3000, 3500, 4000]
|
||||||
|
urls = []
|
||||||
|
for size in sizes:
|
||||||
|
for i in range(0, 4):
|
||||||
|
urls.append('%s/random%sx%s.jpg' %
|
||||||
|
(os.path.dirname(best['url']), size, size))
|
||||||
|
if not args.simple:
|
||||||
|
print_('Testing download speed', end='')
|
||||||
|
dlspeed = downloadSpeed(urls, args.simple)
|
||||||
|
if not args.simple:
|
||||||
|
print_()
|
||||||
|
print_('Download: %0.2f M%s/s' %
|
||||||
|
((dlspeed / 1000 / 1000) * args.units[1], args.units[0]))
|
||||||
|
|
||||||
|
sizesizes = [int(.25 * 1000 * 1000), int(.5 * 1000 * 1000)]
|
||||||
|
sizes = []
|
||||||
|
for size in sizesizes:
|
||||||
|
for i in range(0, 25):
|
||||||
|
sizes.append(size)
|
||||||
|
if not args.simple:
|
||||||
|
print_('Testing upload speed', end='')
|
||||||
|
ulspeed = uploadSpeed(best['url'], sizes, args.simple)
|
||||||
|
if not args.simple:
|
||||||
|
print_()
|
||||||
|
print_('Upload: %0.2f M%s/s' %
|
||||||
|
((ulspeed / 1000 / 1000) * args.units[1], args.units[0]))
|
||||||
|
|
||||||
|
if args.share and args.mini:
|
||||||
|
print_('Cannot generate a speedtest.net share results image while '
|
||||||
|
'testing against a Speedtest Mini server')
|
||||||
|
elif args.share:
|
||||||
|
dlspeedk = int(round((dlspeed / 1000) * 8, 0))
|
||||||
|
ping = int(round(best['latency'], 0))
|
||||||
|
ulspeedk = int(round((ulspeed / 1000) * 8, 0))
|
||||||
|
|
||||||
|
# Build the request to send results back to speedtest.net
|
||||||
|
# We use a list instead of a dict because the API expects parameters
|
||||||
|
# in a certain order
|
||||||
|
apiData = [
|
||||||
|
'download=%s' % dlspeedk,
|
||||||
|
'ping=%s' % ping,
|
||||||
|
'upload=%s' % ulspeedk,
|
||||||
|
'promo=',
|
||||||
|
'startmode=%s' % 'pingselect',
|
||||||
|
'recommendedserverid=%s' % best['id'],
|
||||||
|
'accuracy=%s' % 1,
|
||||||
|
'serverid=%s' % best['id'],
|
||||||
|
'hash=%s' % md5(('%s-%s-%s-%s' %
|
||||||
|
(ping, ulspeedk, dlspeedk, '297aae72'))
|
||||||
|
.encode()).hexdigest()]
|
||||||
|
|
||||||
|
req = Request('http://www.speedtest.net/api/api.php',
|
||||||
|
data='&'.join(apiData).encode())
|
||||||
|
req.add_header('Referer', 'http://c.speedtest.net/flash/speedtest.swf')
|
||||||
|
f = urlopen(req)
|
||||||
|
response = f.read()
|
||||||
|
code = f.code
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
if int(code) != 200:
|
||||||
|
print_('Could not submit results to speedtest.net')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
qsargs = parse_qs(response.decode())
|
||||||
|
resultid = qsargs.get('resultid')
|
||||||
|
if not resultid or len(resultid) != 1:
|
||||||
|
print_('Could not submit results to speedtest.net')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print_('Share results: http://www.speedtest.net/result/%s.png' %
|
||||||
|
resultid[0])
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
try:
|
||||||
|
speedtest()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print_('\nCancelling...')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
||||||
|
# vim:ts=4:sw=4:expandtab
|
17
sources/server/modules/shell_files/arp_cache.sh
Executable file
17
sources/server/modules/shell_files/arp_cache.sh
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
arpCommand=$(command -v arp)
|
||||||
|
|
||||||
|
result=$($arpCommand | awk 'BEGIN {print "["} NR>1 \
|
||||||
|
{print "{ \"address\": \"" $1 "\", " \
|
||||||
|
"\"hw_type\": \"" $2 "\", " \
|
||||||
|
"\"hw_address\": \"" $3 "\", " \
|
||||||
|
"\"flags\": \"" $4 "\", " \
|
||||||
|
"\"mask\": \"" $5 "\" }, " \
|
||||||
|
} \
|
||||||
|
END {print "]"}' \
|
||||||
|
| /bin/sed 'N;$s/},/}/;P;D')
|
||||||
|
|
||||||
|
if [ -z "$result" ]; then echo {}
|
||||||
|
else echo $result
|
||||||
|
fi
|
6
sources/server/modules/shell_files/bandwidth.sh
Executable file
6
sources/server/modules/shell_files/bandwidth.sh
Executable file
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/bash
|
||||||
|
/bin/cat /proc/net/dev \
|
||||||
|
| awk 'BEGIN {print "["} NR>2 {print "{ \"interface\": \"" $1 "\"," \
|
||||||
|
" \"tx\": " $2 "," \
|
||||||
|
" \"rx\": " $10 " }," } END {print "]"}' \
|
||||||
|
| /bin/sed 'N;$s/,\n/\n/;P;D'
|
11
sources/server/modules/shell_files/common_applications.sh
Executable file
11
sources/server/modules/shell_files/common_applications.sh
Executable file
|
@ -0,0 +1,11 @@
|
||||||
|
#!/bin/bash
|
||||||
|
result=$(whereis php node mysql mongo vim python ruby java apache2 nginx openssl vsftpd make \
|
||||||
|
| awk -F: '{if(length($2)==0) { installed="false"; } else { installed="true"; } \
|
||||||
|
print \
|
||||||
|
"{ \
|
||||||
|
\"binary\": \""$1"\", \
|
||||||
|
\"location\": \""$2"\", \
|
||||||
|
\"installed\": "installed" \
|
||||||
|
},"}')
|
||||||
|
|
||||||
|
echo "[" ${result%?} "]"
|
7
sources/server/modules/shell_files/cpu_info.sh
Executable file
7
sources/server/modules/shell_files/cpu_info.sh
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
result=$(/usr/bin/lscpu \
|
||||||
|
| /usr/bin/awk -F: '{print "\""$1"\": \""$2"\"," } '\
|
||||||
|
)
|
||||||
|
|
||||||
|
echo "{" ${result%?} "}"
|
13
sources/server/modules/shell_files/cpu_intensive_processes.sh
Executable file
13
sources/server/modules/shell_files/cpu_intensive_processes.sh
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
result=$(/bin/ps axo pid,user,pcpu,rss,vsz,comm --sort -pcpu,-rss,-vsz \
|
||||||
|
| head -n 15 \
|
||||||
|
| /usr/bin/awk 'BEGIN{OFS=":"} NR>1 {print "{ \"pid\": " $1 \
|
||||||
|
", \"user\": \"" $2 "\"" \
|
||||||
|
", \"cpu%\": " $3 \
|
||||||
|
", \"rss\": " $4 \
|
||||||
|
", \"vsz\": " $5 \
|
||||||
|
", \"cmd\": \"" $6 "\"" "},"\
|
||||||
|
}')
|
||||||
|
|
||||||
|
echo "[" ${result%?} "]"
|
33
sources/server/modules/shell_files/cpu_utilization.sh
Executable file
33
sources/server/modules/shell_files/cpu_utilization.sh
Executable file
|
@ -0,0 +1,33 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# by Paul Colby (http://colby.id.au), no rights reserved ;)
|
||||||
|
|
||||||
|
PREV_TOTAL=0
|
||||||
|
PREV_IDLE=0
|
||||||
|
iteration=0
|
||||||
|
|
||||||
|
while [[ iteration -lt 2 ]]; do
|
||||||
|
# Get the total CPU statistics, discarding the 'cpu ' prefix.
|
||||||
|
CPU=(`sed -n 's/^cpu\s//p' /proc/stat`)
|
||||||
|
IDLE=${CPU[3]} # Just the idle CPU time.
|
||||||
|
|
||||||
|
# Calculate the total CPU time.
|
||||||
|
TOTAL=0
|
||||||
|
for VALUE in "${CPU[@]}"; do
|
||||||
|
let "TOTAL=$TOTAL+$VALUE"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Calculate the CPU usage since we last checked.
|
||||||
|
let "DIFF_IDLE=$IDLE-$PREV_IDLE"
|
||||||
|
let "DIFF_TOTAL=$TOTAL-$PREV_TOTAL"
|
||||||
|
let "DIFF_USAGE=(1000*($DIFF_TOTAL-$DIFF_IDLE)/$DIFF_TOTAL+5)/10"
|
||||||
|
#echo -en "\rCPU: $DIFF_USAGE% \b\b"
|
||||||
|
|
||||||
|
# Remember the total and idle CPU times for the next check.
|
||||||
|
PREV_TOTAL="$TOTAL"
|
||||||
|
PREV_IDLE="$IDLE"
|
||||||
|
|
||||||
|
# Wait before checking again.
|
||||||
|
sleep 1
|
||||||
|
iteration="$iteration+1"
|
||||||
|
done
|
||||||
|
echo -en "$DIFF_USAGE"
|
18
sources/server/modules/shell_files/cron_history.sh
Executable file
18
sources/server/modules/shell_files/cron_history.sh
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
grepCmd=$(which grep)
|
||||||
|
cronLog='/var/log/syslog'
|
||||||
|
numberOfLines='50'
|
||||||
|
|
||||||
|
# Month, Day, Time, Hostname, tag, user,
|
||||||
|
|
||||||
|
result=$($grepCmd -m$numberOfLines CRON $cronLog \
|
||||||
|
| awk '{ s = ""; for (i = 6; i <= NF; i++) s = s $i " "; \
|
||||||
|
print "{\"time\" : \"" $1" "$2" "$3 "\"," \
|
||||||
|
"\"user\" : \"" $6 "\"," \
|
||||||
|
"\"message\" : \"" $5" "s "\"" \
|
||||||
|
"},"
|
||||||
|
}'
|
||||||
|
)
|
||||||
|
|
||||||
|
echo [${result%?}]
|
14
sources/server/modules/shell_files/current_ram.sh
Executable file
14
sources/server/modules/shell_files/current_ram.sh
Executable file
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
awkCmd=`which awk`
|
||||||
|
catCmd=`which cat`
|
||||||
|
grepCmd=`which grep`
|
||||||
|
memInfoFile="/proc/meminfo"
|
||||||
|
|
||||||
|
# References:
|
||||||
|
# Calculations: http://zcentric.com/2012/05/29/mapping-procmeminfo-to-output-of-free-command/
|
||||||
|
# Fields: https://www.kernel.org/doc/Documentation/filesystems/proc.txt
|
||||||
|
|
||||||
|
memInfo=`$catCmd $memInfoFile | $grepCmd 'MemTotal\|MemFree\|Buffers\|Cached'`
|
||||||
|
|
||||||
|
echo $memInfo | $awkCmd '{print "{ \"total\": " ($2/1024) ", \"used\": " ( ($2-($5+$8+$11))/1024 ) ", \"free\": " (($5+$8+$11)/1024) " }" }'
|
4
sources/server/modules/shell_files/disk_partitions.sh
Executable file
4
sources/server/modules/shell_files/disk_partitions.sh
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/bash
|
||||||
|
result=$(/bin/df -Ph | awk 'NR>1 {print "{\"file_system\": \"" $1 "\", \"size\": \"" $2 "\", \"used\": \"" $3 "\", \"avail\": \"" $4 "\", \"used%\": \"" $5 "\", \"mounted\": \"" $6 "\"},"}')
|
||||||
|
|
||||||
|
echo [ ${result%?} ]
|
40
sources/server/modules/shell_files/download_transfer_rate.sh
Executable file
40
sources/server/modules/shell_files/download_transfer_rate.sh
Executable file
|
@ -0,0 +1,40 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
files=(/sys/class/net/*)
|
||||||
|
pos=$(( ${#files[*]} - 1 ))
|
||||||
|
last=${files[$pos]}
|
||||||
|
|
||||||
|
json_output="{"
|
||||||
|
|
||||||
|
for interface in "${files[@]}"
|
||||||
|
do
|
||||||
|
basename=$(basename "$interface")
|
||||||
|
|
||||||
|
# find the number of bytes transfered for this interface
|
||||||
|
in1=$(cat /sys/class/net/"$basename"/statistics/rx_bytes)
|
||||||
|
|
||||||
|
# wait a second
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# check same interface again
|
||||||
|
in2=$(cat /sys/class/net/"$basename"/statistics/rx_bytes)
|
||||||
|
|
||||||
|
# get the difference (transfer rate)
|
||||||
|
in_bytes=$((in2 - in1))
|
||||||
|
|
||||||
|
# convert transfer rate to KB
|
||||||
|
in_kbytes=$((in_bytes / 1024))
|
||||||
|
|
||||||
|
# convert transfer rate to KB
|
||||||
|
json_output="$json_output \"$basename\": $in_kbytes"
|
||||||
|
|
||||||
|
# if it is not the last line
|
||||||
|
if [[ ! $interface == $last ]]
|
||||||
|
then
|
||||||
|
# add a comma to the line (JSON formatting)
|
||||||
|
json_output="$json_output,"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# close the JSON object & print to screen
|
||||||
|
echo "$json_output}"
|
28
sources/server/modules/shell_files/general_info.sh
Executable file
28
sources/server/modules/shell_files/general_info.sh
Executable file
|
@ -0,0 +1,28 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
function displaytime {
|
||||||
|
local T=$1
|
||||||
|
local D=$((T/60/60/24))
|
||||||
|
local H=$((T/60/60%24))
|
||||||
|
local M=$((T/60%60))
|
||||||
|
local S=$((T%60))
|
||||||
|
[[ $D > 0 ]] && printf '%d days ' $D
|
||||||
|
[[ $H > 0 ]] && printf '%d hours ' $H
|
||||||
|
[[ $M > 0 ]] && printf '%d minutes ' $M
|
||||||
|
[[ $D > 0 || $H > 0 || $M > 0 ]] && printf 'and '
|
||||||
|
printf '%d seconds\n' $S
|
||||||
|
}
|
||||||
|
|
||||||
|
lsbRelease=$(/usr/bin/lsb_release -ds | sed -e 's/^"//' -e 's/"$//')
|
||||||
|
uname=$(/bin/uname -r | sed -e 's/^"//' -e 's/"$//')
|
||||||
|
os=`echo $lsbRelease $uname`
|
||||||
|
hostname=$(/bin/hostname)
|
||||||
|
uptime_seconds=$(/bin/cat /proc/uptime | awk '{print $1}')
|
||||||
|
server_time=$(date)
|
||||||
|
|
||||||
|
echo { \
|
||||||
|
\"OS\": \"$os\", \
|
||||||
|
\"Hostname\": \"$hostname\", \
|
||||||
|
\"Uptime\": \" $(displaytime ${uptime_seconds%.*}) \", \
|
||||||
|
\"Server Time\": \"$server_time\" \
|
||||||
|
}
|
9
sources/server/modules/shell_files/internet_speed.sh
Executable file
9
sources/server/modules/shell_files/internet_speed.sh
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SCRIPTPATH=`dirname $(readlink -f $0)`
|
||||||
|
SPEED_TEST_SCRIPT=$SCRIPTPATH"/../python_files/speedtest_cli.py"
|
||||||
|
|
||||||
|
$SPEED_TEST_SCRIPT \
|
||||||
|
| grep 'Upload\|Download' \
|
||||||
|
| awk 'BEGIN {print "{"} {print "\"" $1 "\": \"" $2 " " $3 "\"," } END {print "}"}' \
|
||||||
|
| /bin/sed 'N;$s/",/"/;P;D'
|
7
sources/server/modules/shell_files/io_stats.sh
Executable file
7
sources/server/modules/shell_files/io_stats.sh
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
result=$(/bin/cat /proc/diskstats | /usr/bin/awk \
|
||||||
|
'{ if($4==0 && $8==0 && $12==0 && $13==0) next } \
|
||||||
|
{print "{ \"device\": \"" $3 "\", \"reads\": \""$4"\", \"writes\": \"" $8 "\", \"in_progress\": \"" $12 "\", \"time_in_io\": \"" $13 "\"},"}'
|
||||||
|
)
|
||||||
|
|
||||||
|
echo [ ${result%?} ]
|
15
sources/server/modules/shell_files/ip_addresses.sh
Executable file
15
sources/server/modules/shell_files/ip_addresses.sh
Executable file
|
@ -0,0 +1,15 @@
|
||||||
|
#!/bin/bash
|
||||||
|
awkCmd=`which awk`
|
||||||
|
grepCmd=`which grep`
|
||||||
|
sedCmd=`which sed`
|
||||||
|
ifconfigCmd=`which ifconfig`
|
||||||
|
trCmd=`which tr`
|
||||||
|
digCmd=`which dig`
|
||||||
|
|
||||||
|
externalIp=`$digCmd +short myip.opendns.com @resolver1.opendns.com`
|
||||||
|
|
||||||
|
$ifconfigCmd \
|
||||||
|
| $grepCmd -B1 "inet addr" \
|
||||||
|
| $awkCmd '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }' \
|
||||||
|
| $awkCmd -v exIp="$externalIp" -F: 'BEGIN {print "["} { print "{ \"interface\": \"" $1 "\", \"ip\": \"" $3 "\" },"} END {print "{ \"interface\": \"external\", \"ip\": \""exIp"\" } ]"}' \
|
||||||
|
| $trCmd -d '\r\n'
|
10
sources/server/modules/shell_files/load_avg.sh
Executable file
10
sources/server/modules/shell_files/load_avg.sh
Executable file
|
@ -0,0 +1,10 @@
|
||||||
|
#!/bin/bash
|
||||||
|
numberOfCores=$(/bin/grep -c 'model name' /proc/cpuinfo)
|
||||||
|
|
||||||
|
if [ $numberOfCores -eq 0 ]; then
|
||||||
|
numberOfCores=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
result=$(/bin/cat /proc/loadavg | /usr/bin/awk '{print "{ \"1_min_avg\": " ($1*100)/'$numberOfCores' ", \"5_min_avg\": " ($2*100)/'$numberOfCores' ", \"15_min_avg\": " ($3*100)/'$numberOfCores' "}," }')
|
||||||
|
|
||||||
|
echo ${result%?}
|
4
sources/server/modules/shell_files/logged_in_users.sh
Executable file
4
sources/server/modules/shell_files/logged_in_users.sh
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/bash
|
||||||
|
result=$(COLUMNS=300 /usr/bin/w -h | /usr/bin/awk '{print "{\"user\": \"" $1 "\", \"from\": \"" $3 "\", \"when\": \"" $4 "\"},"}')
|
||||||
|
|
||||||
|
echo [ ${result%?} ]
|
7
sources/server/modules/shell_files/memcached.sh
Executable file
7
sources/server/modules/shell_files/memcached.sh
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
echo "stats" \
|
||||||
|
| /bin/nc -w 1 127.0.0.1 11211 \
|
||||||
|
| /bin/grep 'bytes' \
|
||||||
|
| /usr/bin/awk 'BEGIN {print "{"} {print "\"" $2 "\": " $3 } END {print "}"}' \
|
||||||
|
| /usr/bin/tr '\r' ',' \
|
||||||
|
| /bin/sed 'N;$s/,\n/\n/;P;D'
|
4
sources/server/modules/shell_files/memory_info.sh
Executable file
4
sources/server/modules/shell_files/memory_info.sh
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/bash
|
||||||
|
/bin/cat /proc/meminfo \
|
||||||
|
| /usr/bin/awk -F: 'BEGIN {print "{"} {print "\"" $1 "\": \"" $2 "\"," } END {print "}"}' \
|
||||||
|
| /bin/sed 'N;$s/,\n/\n/;P;D'
|
13
sources/server/modules/shell_files/network_connections.sh
Executable file
13
sources/server/modules/shell_files/network_connections.sh
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
#!/bin/bash
|
||||||
|
netstatCmd=`which netstat`
|
||||||
|
awkCmd=`which awk`
|
||||||
|
sortCmd=`which sort`
|
||||||
|
uniqCmd=`which uniq`
|
||||||
|
sedCmd=`which sed`
|
||||||
|
|
||||||
|
$netstatCmd -ntu \
|
||||||
|
| $awkCmd 'NR>2 {print $5}' \
|
||||||
|
| $sortCmd \
|
||||||
|
| $uniqCmd -c \
|
||||||
|
| $awkCmd 'BEGIN {print "["} {print "{ \"connections\": " $1 ", \"address\": \"" $2 "\" }," } END {print "]"}' \
|
||||||
|
| $sedCmd 'N;$s/},/}/;P;D'
|
7
sources/server/modules/shell_files/number_of_cpu_cores.sh
Executable file
7
sources/server/modules/shell_files/number_of_cpu_cores.sh
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
numberOfCores=$(/bin/grep -c 'model name' /proc/cpuinfo)
|
||||||
|
|
||||||
|
if [length($numberOfCores)]; then
|
||||||
|
echo "cannnot be found";
|
||||||
|
fi
|
28
sources/server/modules/shell_files/ping.sh
Executable file
28
sources/server/modules/shell_files/ping.sh
Executable file
|
@ -0,0 +1,28 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# http://askubuntu.com/questions/413367/ping-multiple-ips-using-bash
|
||||||
|
|
||||||
|
# get absolute path to config file
|
||||||
|
SCRIPTPATH=`dirname $(readlink -f $0)`
|
||||||
|
CONFIG_PATH=$SCRIPTPATH"/../config/ping_hosts"
|
||||||
|
|
||||||
|
catCmd=`which cat`
|
||||||
|
pingCmd=`which ping`
|
||||||
|
awkCmd=`which awk`
|
||||||
|
sedCmd=`which sed`
|
||||||
|
numOfLinesInConfig=`$sedCmd -n '$=' $CONFIG_PATH`
|
||||||
|
result='['
|
||||||
|
|
||||||
|
{ $catCmd $CONFIG_PATH; echo; } \
|
||||||
|
| while read output
|
||||||
|
do
|
||||||
|
singlePing=$($pingCmd -qc 2 $output \
|
||||||
|
| $awkCmd -F/ 'BEGIN { endLine="}," } /^rtt/ { if ('$numOfLinesInConfig'==1){endLine="}"} print "{" "\"host\": \"'$output'\", \"ping\": " $5 " " endLine }' \
|
||||||
|
)
|
||||||
|
numOfLinesInConfig=$(($numOfLinesInConfig-1))
|
||||||
|
result=$result$singlePing
|
||||||
|
if [ $numOfLinesInConfig -eq 1 ]
|
||||||
|
then
|
||||||
|
echo $result"]"
|
||||||
|
fi
|
||||||
|
done \
|
||||||
|
| $sedCmd 's/\},]/}]/g'
|
12
sources/server/modules/shell_files/ram_intensive_processes.sh
Executable file
12
sources/server/modules/shell_files/ram_intensive_processes.sh
Executable file
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
result=$(/bin/ps axo pid,user,pmem,rss,vsz,comm --sort -pmem,-rss,-vsz \
|
||||||
|
| head -n 15 \
|
||||||
|
| /usr/bin/awk 'NR>1 {print "{ \"pid\": " $1 \
|
||||||
|
", \"user\": \"" $2 \
|
||||||
|
"\", \"mem%\": " $3 \
|
||||||
|
", \"rss\": " $4 \
|
||||||
|
", \"vsz\": " $5 \
|
||||||
|
", \"cmd\": \"" $6 \
|
||||||
|
"\"},"}')
|
||||||
|
|
||||||
|
echo [ ${result%?} ]
|
10
sources/server/modules/shell_files/recent_account_logins.sh
Executable file
10
sources/server/modules/shell_files/recent_account_logins.sh
Executable file
|
@ -0,0 +1,10 @@
|
||||||
|
#!/bin/bash
|
||||||
|
result=$(/usr/bin/lastlog -t 365 \
|
||||||
|
| /usr/bin/awk 'NR>1 {\
|
||||||
|
print "{ \
|
||||||
|
\"user\": \"" $1 "\", \
|
||||||
|
\"ip\": \"" $3 "\","" \
|
||||||
|
\"date\": \"" $5" "$6" "$7" "$8" "$9 "\"},"
|
||||||
|
}'
|
||||||
|
)
|
||||||
|
echo [ ${result%?} ]
|
18
sources/server/modules/shell_files/redis.sh
Executable file
18
sources/server/modules/shell_files/redis.sh
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
########### Enter Your Redis Password HERE #########
|
||||||
|
redisPassword=''
|
||||||
|
########### Enter Your Redis Password HERE #########
|
||||||
|
|
||||||
|
redisCommand=$(which redis-cli);
|
||||||
|
|
||||||
|
if [ -n "$redisPassword" ]; then
|
||||||
|
redisCommand="$redisCommand -a $redisPassword"
|
||||||
|
fi
|
||||||
|
|
||||||
|
result=$($redisCommand INFO \
|
||||||
|
| grep 'redis_version\|connected_clients\|connected_slaves\|used_memory_human\|total_connections_received\|total_commands_processed' \
|
||||||
|
| awk -F: '{print "\"" $1 "\":" "\"" $2 }' \
|
||||||
|
| tr '\r' '"' | tr '\n' ','
|
||||||
|
)
|
||||||
|
echo { ${result%?} }
|
88
sources/server/modules/shell_files/scheduled_crons.sh
Executable file
88
sources/server/modules/shell_files/scheduled_crons.sh
Executable file
|
@ -0,0 +1,88 @@
|
||||||
|
#!/bin/bash
|
||||||
|
######
|
||||||
|
# Credit: http://stackoverflow.com/questions/134906/how-do-i-list-all-cron-jobs-for-all-users#answer-137173
|
||||||
|
######
|
||||||
|
|
||||||
|
catCmd=`which cat`
|
||||||
|
awkCmd=`which awk`
|
||||||
|
sedCmd=`which sed`
|
||||||
|
egrepCmd=`which egrep`
|
||||||
|
echoCmd=`which echo`
|
||||||
|
crontabCmd=`which crontab`
|
||||||
|
|
||||||
|
# System-wide crontab file and cron job directory. Change these for your system.
|
||||||
|
CRONTAB='/etc/crontab'
|
||||||
|
CRONDIR='/etc/cron.d'
|
||||||
|
|
||||||
|
# Single tab character. Annoyingly necessary.
|
||||||
|
tab=$(echo -en "\t")
|
||||||
|
|
||||||
|
# Given a stream of crontab lines, exclude non-cron job lines, replace
|
||||||
|
# whitespace characters with a single space, and remove any spaces from the
|
||||||
|
# beginning of each line.
|
||||||
|
function clean_cron_lines() {
|
||||||
|
while read line ; do
|
||||||
|
$echoCmd "${line}" |
|
||||||
|
$egrepCmd --invert-match '^($|\s*#|\s*[[:alnum:]_]+=)' |
|
||||||
|
$sedCmd --regexp-extended "s/\s+/ /g" |
|
||||||
|
$sedCmd --regexp-extended "s/^ //"
|
||||||
|
done;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Given a stream of cleaned crontab lines, $echoCmd any that don't include the
|
||||||
|
# run-parts command, and for those that do, show each job file in the run-parts
|
||||||
|
# directory as if it were scheduled explicitly.
|
||||||
|
function lookup_run_parts() {
|
||||||
|
while read line ; do
|
||||||
|
match=$($echoCmd "${line}" | $egrepCmd -o 'run-parts (-{1,2}\S+ )*\S+')
|
||||||
|
|
||||||
|
if [[ -z "${match}" ]] ; then
|
||||||
|
$echoCmd "${line}"
|
||||||
|
else
|
||||||
|
cron_fields=$($echoCmd "${line}" | cut -f1-6 -d' ')
|
||||||
|
cron_job_dir=$($echoCmd "${match}" | awk '{print $NF}')
|
||||||
|
|
||||||
|
if [[ -d "${cron_job_dir}" ]] ; then
|
||||||
|
for cron_job_file in "${cron_job_dir}"/* ; do # */ <not a comment>
|
||||||
|
[[ -f "${cron_job_file}" ]] && $echoCmd "${cron_fields} ${cron_job_file}"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Temporary file for crontab lines.
|
||||||
|
temp=$(mktemp) || exit 1
|
||||||
|
|
||||||
|
# Add all of the jobs from the system-wide crontab file.
|
||||||
|
$catCmd "${CRONTAB}" | clean_cron_lines | lookup_run_parts >"${temp}"
|
||||||
|
|
||||||
|
# Add all of the jobs from the system-wide cron directory.
|
||||||
|
$catCmd "${CRONDIR}"/* | clean_cron_lines >>"${temp}" # */ <not a comment>
|
||||||
|
|
||||||
|
# Add each user's crontab (if it exists). Insert the user's name between the
|
||||||
|
# five time fields and the command.
|
||||||
|
while read user ; do
|
||||||
|
$crontabCmd -l -u "${user}" 2>/dev/null |
|
||||||
|
clean_cron_lines |
|
||||||
|
$sedCmd --regexp-extended "s/^((\S+ +){5})(.+)$/\1${user} \3/" >>"${temp}"
|
||||||
|
done < <(cut --fields=1 --delimiter=: /etc/passwd)
|
||||||
|
|
||||||
|
# Output the collected crontab lines.
|
||||||
|
|
||||||
|
## Changes: Parses output into JSON
|
||||||
|
|
||||||
|
$catCmd "${temp}" \
|
||||||
|
| awk 'BEGIN {print "["} \
|
||||||
|
{print "{ \"min(s)\": \"" $1 \
|
||||||
|
"\", \"hours(s)\": \"" $2 "\", " \
|
||||||
|
" \"day(s)\": \"" $3 "\", " \
|
||||||
|
" \"month\": \"" $4 "\", " \
|
||||||
|
" \"weekday\": \"" $5 "\", " \
|
||||||
|
" \"user\": \"" $6 "\", " \
|
||||||
|
" \"command\": \"" $7$8$9$10 "\" " \
|
||||||
|
"}," } \
|
||||||
|
END {print "]"}' \
|
||||||
|
| $sedCmd 'N;$s/,\n/\n/;P;D'
|
||||||
|
|
||||||
|
rm --force "${temp}"
|
5
sources/server/modules/shell_files/swap.sh
Executable file
5
sources/server/modules/shell_files/swap.sh
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/bash
|
||||||
|
result=$(/bin/cat /proc/swaps \
|
||||||
|
| /usr/bin/awk 'NR>1 {print "{ \"filename\": \"" $1"\", \"type\": \""$2"\", \"size\": \""$3"\", \"used\": \""$4"\", \"priority\": \""$5"\"}," }'
|
||||||
|
)
|
||||||
|
echo [ ${result%?} ]
|
40
sources/server/modules/shell_files/upload_transfer_rate.sh
Executable file
40
sources/server/modules/shell_files/upload_transfer_rate.sh
Executable file
|
@ -0,0 +1,40 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
files=(/sys/class/net/*)
|
||||||
|
pos=$(( ${#files[*]} - 1 ))
|
||||||
|
last=${files[$pos]}
|
||||||
|
|
||||||
|
json_output="{"
|
||||||
|
|
||||||
|
for interface in "${files[@]}"
|
||||||
|
do
|
||||||
|
basename=$(basename "$interface")
|
||||||
|
|
||||||
|
# find the number of bytes transfered for this interface
|
||||||
|
out1=$(cat /sys/class/net/"$basename"/statistics/tx_bytes)
|
||||||
|
|
||||||
|
# wait a second
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# check same interface again
|
||||||
|
out2=$(cat /sys/class/net/"$basename"/statistics/tx_bytes)
|
||||||
|
|
||||||
|
# get the difference (transfer rate)
|
||||||
|
out_bytes=$((out2 - out1))
|
||||||
|
|
||||||
|
# convert transfer rate to KB
|
||||||
|
out_kbytes=$((out_bytes / 1024))
|
||||||
|
|
||||||
|
# convert transfer rate to KB
|
||||||
|
json_output="$json_output \"$basename\": $out_kbytes"
|
||||||
|
|
||||||
|
# if it is not the last line
|
||||||
|
if [[ ! $interface == $last ]]
|
||||||
|
then
|
||||||
|
# add a comma to the line (JSON formatting)
|
||||||
|
json_output="$json_output,"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# close the JSON object & print to screen
|
||||||
|
echo "$json_output}"
|
14
sources/server/modules/shell_files/user_accounts.sh
Executable file
14
sources/server/modules/shell_files/user_accounts.sh
Executable file
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/bash
|
||||||
|
result=$(/usr/bin/awk -F: '{ \
|
||||||
|
if ($3<=499){userType="system";} \
|
||||||
|
else {userType="user";} \
|
||||||
|
print "{ \"type\": \"" userType "\"" ", \"user\": \"" $1 "\", \"home\": \"" $6 "\" }," }' < /etc/passwd
|
||||||
|
)
|
||||||
|
|
||||||
|
length=$(echo ${#result})
|
||||||
|
|
||||||
|
if [ $length -eq 0 ]; then
|
||||||
|
result=$(getent passwd | /usr/bin/awk -F: '{ if ($3<=499){userType="system";} else {userType="user";} print "{ \"type\": \"" userType "\"" ", \"user\": \"" $1 "\", \"home\": \"" $6 "\" }," }')
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo [ ${result%?} ]
|
10
sources/templates/app/base-plugin.html
Normal file
10
sources/templates/app/base-plugin.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<div class="plugin">
|
||||||
|
<top-bar
|
||||||
|
heading="heading"
|
||||||
|
last-updated="lastGet"
|
||||||
|
info="info"
|
||||||
|
refresh="getData()">
|
||||||
|
</top-bar>
|
||||||
|
|
||||||
|
<div class="plugin-body" ng-transclude></div>
|
||||||
|
</div>
|
22
sources/templates/app/key-value-list-plugin.html
Normal file
22
sources/templates/app/key-value-list-plugin.html
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<plugin
|
||||||
|
heading="{{ heading }}"
|
||||||
|
last-updated="lastGet"
|
||||||
|
on-refresh="getData()"
|
||||||
|
info="{{ info }}">
|
||||||
|
|
||||||
|
<loader ng-if="!tableRows"></loader>
|
||||||
|
|
||||||
|
<div class="animate" ng-show="tableRows">
|
||||||
|
<table class="key-value-list">
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="(name, value) in tableRows">
|
||||||
|
<td><strong>{{ name }}</strong></td>
|
||||||
|
<td>{{ value }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<no-data ng-show="emptyResult"></no-data>
|
||||||
|
</plugin>
|
20
sources/templates/app/line-chart-plugin.html
Normal file
20
sources/templates/app/line-chart-plugin.html
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<div class="plugin">
|
||||||
|
|
||||||
|
<top-bar heading="heading" last-updated="lastGet" no-refresh-btn></top-bar>
|
||||||
|
|
||||||
|
<div class="plugin-body no-padding">
|
||||||
|
|
||||||
|
<canvas class="canvas" width="400" height="200"></canvas>
|
||||||
|
|
||||||
|
<table border="0" class="metrics-table">
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="metric in metrics">
|
||||||
|
<td><strong>{{ metric.name }}</strong></td>
|
||||||
|
<td>{{ metric.data }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</plugin>
|
4
sources/templates/app/loading.html
Normal file
4
sources/templates/app/loading.html
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<div class="lead" style="text-align: center;">
|
||||||
|
<loader></loader>
|
||||||
|
Loading...
|
||||||
|
</div>
|
26
sources/templates/app/multi-line-chart-plugin.html
Normal file
26
sources/templates/app/multi-line-chart-plugin.html
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<div class="plugin">
|
||||||
|
<top-bar heading="heading" last-updated="lastGet" no-refresh-btn></top-bar>
|
||||||
|
|
||||||
|
<div class="plugin-body no-padding">
|
||||||
|
|
||||||
|
<canvas class="canvas" width="400" height="200"></canvas>
|
||||||
|
|
||||||
|
<table class="metrics-table" border="0">
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="metric in metricsArray">
|
||||||
|
<td>
|
||||||
|
<div
|
||||||
|
class="metric-square"
|
||||||
|
style="display: inline-block; border: 1px solid {{metric.color}}; width: 8px; height: 8px; background: {{metric.color}}">
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>{{ metric.name }}</td>
|
||||||
|
<td>{{ metric.data }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</plugin>
|
8
sources/templates/app/navbar.html
Normal file
8
sources/templates/app/navbar.html
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<br>
|
||||||
|
<ul>
|
||||||
|
<li ng-class="{active: isActive(navItem) }" ng-repeat="navItem in items">
|
||||||
|
<a href="#/{{navItem}}">
|
||||||
|
{{getNavItemName(navItem)}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
5
sources/templates/app/progress-bar-plugin.html
Normal file
5
sources/templates/app/progress-bar-plugin.html
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<div class="progress-bar-container">
|
||||||
|
<div class="progress-bar" style="width:{{width}};">
|
||||||
|
<div style="width: {{ (value/max) * 100 }}%;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
40
sources/templates/app/table-data-plugin.html
Normal file
40
sources/templates/app/table-data-plugin.html
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<plugin
|
||||||
|
heading="{{ heading }}"
|
||||||
|
last-updated="lastGet"
|
||||||
|
on-refresh="getData()"
|
||||||
|
info="{{ info }}">
|
||||||
|
|
||||||
|
<loader ng-if="!tableRows"></loader>
|
||||||
|
|
||||||
|
<div class="animate" ng-show="tableRows">
|
||||||
|
|
||||||
|
<table class="table-data-plugin">
|
||||||
|
<thead>
|
||||||
|
<tr class="table-data-filter-container" ng-show="tableRows.length">
|
||||||
|
<th colspan="{{ tableHeaders.length }}" class="filter-container">
|
||||||
|
<input class="filter" ng-model="keyword" placeholder="Search">
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th ng-repeat="header in tableHeaders track by $index">
|
||||||
|
<a href="" ng-click="setSortColumn(header)">{{ header }}</a>
|
||||||
|
<span class="column-sort-caret">
|
||||||
|
{{ (header === sortByColumn && !sortReverse) ? '▲': ''; }}
|
||||||
|
{{ (header === sortByColumn && sortReverse) ? '▼': ''; }}
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="row in tableRows | filter:keyword">
|
||||||
|
<td ng-repeat="header in tableHeaders track by $index">
|
||||||
|
{{ row[header] }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<no-data ng-show="emptyResult"></no-data>
|
||||||
|
</plugin>
|
12
sources/templates/app/theme-switcher.html
Normal file
12
sources/templates/app/theme-switcher.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<div id="theme-switcher" class="{{ (themeSwitcherOpen) ? 'open': '' }}">
|
||||||
|
|
||||||
|
<div class="settings-icon" ng-click="toggleThemeSwitcher()">⚙</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="option {{ (theme.selected) ? 'selected': '' }}"
|
||||||
|
ng-repeat="theme in themes"
|
||||||
|
ng-click="switchTheme(theme)">
|
||||||
|
{{ theme.name }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
4
sources/templates/app/ui-elements/last-update.html
Normal file
4
sources/templates/app/ui-elements/last-update.html
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<span ng-hide="timestamp">Loading...</span>
|
||||||
|
<small alt="Last Update Timestamp">
|
||||||
|
<span ng-show="timestamp">{{ timestamp | date:'hh:mm:ss a' }}</span>
|
||||||
|
</small>
|
10
sources/templates/app/ui-elements/top-bar.html
Normal file
10
sources/templates/app/ui-elements/top-bar.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<div class="top-bar">
|
||||||
|
<last-update timestamp="lastUpdated"></last-update>
|
||||||
|
<span class="qs">
|
||||||
|
{{ heading }}
|
||||||
|
<span class="popover above" ng-if="info">
|
||||||
|
{{ info }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<refresh-btn refresh="refresh()"></refresh-btn>
|
||||||
|
</div>
|
5
sources/templates/modules/cpu-load.html
Normal file
5
sources/templates/modules/cpu-load.html
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<multi-line-chart-plugin
|
||||||
|
heading="CPU Avg Load"
|
||||||
|
module-name="load_avg"
|
||||||
|
units="units">
|
||||||
|
</multi-line-chart-plugin>
|
14
sources/templates/modules/cpu-utilization-chart.html
Normal file
14
sources/templates/modules/cpu-utilization-chart.html
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
<line-chart-plugin
|
||||||
|
|
||||||
|
heading="CPU Utilization"
|
||||||
|
module-name="cpu_utilization"
|
||||||
|
color="0,255,0"
|
||||||
|
|
||||||
|
max-value="max"
|
||||||
|
min-value="min"
|
||||||
|
refresh-rate="1500"
|
||||||
|
|
||||||
|
get-display-value="displayValue"
|
||||||
|
metrics="utilMetrics">
|
||||||
|
</line-chart-plugin>
|
39
sources/templates/modules/disk-space.html
Normal file
39
sources/templates/modules/disk-space.html
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<plugin
|
||||||
|
heading="Disk Partitions"
|
||||||
|
last-updated="lastGet"
|
||||||
|
on-refresh="getData()">
|
||||||
|
|
||||||
|
<loader ng-hide="diskSpaceData"></loader>
|
||||||
|
|
||||||
|
<table ng-show="diskSpaceData">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th></th>
|
||||||
|
<th>Stats</th>
|
||||||
|
<th>Used</th>
|
||||||
|
<th>Mount Path</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="partition in diskSpaceData">
|
||||||
|
<td>{{partition['file_system']}}</td>
|
||||||
|
<td>
|
||||||
|
<progress-bar-plugin
|
||||||
|
width="70px"
|
||||||
|
value="{{ getKB(partition['used']) }}"
|
||||||
|
max="{{ getKB(partition['size']) }}">
|
||||||
|
</progress-bar-plugin>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ partition['used'] }} / {{ partition['size'] }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ partition['used%'] }}
|
||||||
|
</td>
|
||||||
|
<td>{{ partition['mounted'] }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</plugin>
|
5
sources/templates/modules/download-transfer-rate.html
Normal file
5
sources/templates/modules/download-transfer-rate.html
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<multi-line-chart-plugin
|
||||||
|
heading="Download Transfer Rate"
|
||||||
|
module-name="download_transfer_rate"
|
||||||
|
units="units">
|
||||||
|
</multi-line-chart-plugin>
|
14
sources/templates/modules/ram-chart.html
Normal file
14
sources/templates/modules/ram-chart.html
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<line-chart-plugin
|
||||||
|
ng-if="maxRam"
|
||||||
|
|
||||||
|
heading="RAM Usage"
|
||||||
|
module-name="current_ram"
|
||||||
|
color="0,255,0"
|
||||||
|
|
||||||
|
max-value="maxRam"
|
||||||
|
min-value="minRam"
|
||||||
|
refresh-rate="1000"
|
||||||
|
|
||||||
|
get-display-value="ramToDisplay"
|
||||||
|
metrics="ramMetrics">
|
||||||
|
</line-chart-plugin>
|
5
sources/templates/modules/upload-transfer-rate.html
Normal file
5
sources/templates/modules/upload-transfer-rate.html
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<multi-line-chart-plugin
|
||||||
|
heading="Upload Transfer Rate"
|
||||||
|
module-name="upload_transfer_rate"
|
||||||
|
units="units">
|
||||||
|
</multi-line-chart-plugin>
|
5
sources/templates/ping-speeds.html
Normal file
5
sources/templates/ping-speeds.html
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<table-data-plugin
|
||||||
|
heading="Ping Speeds"
|
||||||
|
module-name="ping"
|
||||||
|
table-headers="pingTableConfig">
|
||||||
|
</table-data-plugin>
|
3
sources/templates/sections/accounts.html
Normal file
3
sources/templates/sections/accounts.html
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<server-accounts></server-accounts>
|
||||||
|
<logged-in-accounts></logged-in-accounts>
|
||||||
|
<recent-logins></recent-logins>
|
3
sources/templates/sections/applications.html
Normal file
3
sources/templates/sections/applications.html
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<common-applications></common-applications>
|
||||||
|
<memcached></memcached>
|
||||||
|
<redis></redis>
|
6
sources/templates/sections/basic-info.html
Normal file
6
sources/templates/sections/basic-info.html
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<machine-info></machine-info>
|
||||||
|
<memory-info></memory-info>
|
||||||
|
<cpu-info></cpu-info>
|
||||||
|
<scheduled-crons></scheduled-crons>
|
||||||
|
<cron-history></cron-history>
|
||||||
|
<io-stats></io-stats>
|
8
sources/templates/sections/network.html
Normal file
8
sources/templates/sections/network.html
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<upload-transfer-rate-chart></upload-transfer-rate-chart>
|
||||||
|
<download-transfer-rate-chart></download-transfer-rate-chart>
|
||||||
|
<ip-addresses></ip-addresses>
|
||||||
|
<network-connections></network-connections>
|
||||||
|
<arp-cache-table></arp-cache-table>
|
||||||
|
<ping-speeds></ping-speeds>
|
||||||
|
<bandwidth></bandwidth>
|
||||||
|
<internet-speed></internet-speed>
|
7
sources/templates/sections/system-status.html
Normal file
7
sources/templates/sections/system-status.html
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<ram-chart></ram-chart>
|
||||||
|
<cpu-avg-load-chart></cpu-avg-load-chart>
|
||||||
|
<cpu-utilization-chart></cpu-utilization-chart>
|
||||||
|
<ram-intensive-processes></ram-intensive-processes>
|
||||||
|
<cpu-intensive-processes></cpu-intensive-processes>
|
||||||
|
<swap-usage></swap-usage>
|
||||||
|
<disk-space></disk-space>
|
Loading…
Reference in a new issue