diff --git a/manager/ModuleRequest.php b/manager/ModuleRequest.php index 9a93ed4..625f705 100755 --- a/manager/ModuleRequest.php +++ b/manager/ModuleRequest.php @@ -270,7 +270,6 @@ // Si aucune permission n'est definie if( !isset($method['permissions']) ) return true; - /* [2] Gestion si un @token est defini =========================================================*/ if( Database::check('sha1', $token) ){ @@ -289,10 +288,15 @@ $local_permissions = $token_permissions; - /* [3] Gestion si aucun token, avec utilisateu connecte + /* [3] Gestion si aucun token, avec utilisateur connecté =========================================================*/ - }else + }else if( isset($_SESSION['permission']) ) $local_permissions = $_SESSION['permission']; + // Si ni token, ni SESSION, erreur + else{ + $this->error = ManagerError::PermissionError; + return false; + } /* [4] Verification des droits parmi les permissions donnees diff --git a/phpunit/coverage/Database.php.html b/phpunit/coverage/Database.php.html index 491f6fb..e49482d 100755 --- a/phpunit/coverage/Database.php.html +++ b/phpunit/coverage/Database.php.html @@ -297,7 +297,7 @@
45
46
        /* retourne une instance de la classe */
47
        public static function getInstance(){ -
48
            if( self::$instance == null || self::$error != ManagerError::Success ){ // Si aucune instance existante OU erreur de connection +
48
            if( self::$instance == null || self::$error != ManagerError::Success ){ // Si aucune instance existante OU erreur de connection
49
50
                // chargement de la configuration du server SQL
51
                if( !isset($_SERVER['HTTP_HOST']) || isset($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST'] == 'socioview' ) @@ -310,14 +310,14 @@
58
59
            }
60
             -
61
            return self::$instance; +
61
            return self::$instance;
62
        }
63
64
        /* retourne la connection statique */
65
        public static function getPDO(){ -
66
            $instance = self::getInstance(); +
66
            $instance = self::getInstance();
67
-
68
            return self::$pdo; +
68
            return self::$pdo;
69
        }
70
71
@@ -435,17 +435,17 @@
183
        *
184
        */
185
        public static function check($type, $value){ -
186
            $checker = true; +
186
            $checker = true;
187
188
            /* [0] On verifie que $value n'est pas nul
189
            =========================================================*/ -
190
            if( is_null($value) ) return false; +
190
            if( is_null($value) ) return false;
191
192
193
194
            /* [1] Si de type VARCHAR(min, max)
195
            =========================================================*/ -
196
            if( preg_match('/^varchar\((\d+), ?(\d+)\)$/', $type, $match) ){ +
196
            if( preg_match('/^varchar\((\d+), ?(\d+)\)$/', $type, $match) ){
197
                // On recupere la taille min
198
                $min = (int) $match[1];
199
                // On recupere la taille max @@ -458,7 +458,7 @@
206
207
            /* [2] Si de type ARRAY(type_elements)
208
            =========================================================*/ -
209
            if( preg_match('/^array<(.+)>$/', $type, $match) ){ +
209
            if( preg_match('/^array<(.+)>$/', $type, $match) ){
210
                // Si c'est pas un tableau on retourne une erreur
211
                if( !is_array($value) )
212
                    return false; @@ -480,22 +480,22 @@
228
            =========================================================*/            
229
            switch($type){
230
                // Entier positif (id dans BDD) -
231
                case 'id': -
232
                    return $checker && is_numeric($value) && $value <= 2147483647 && $value >= 0; +
231
                case 'id': +
232
                    return $checker && is_numeric($value) && $value <= 2147483647 && $value >= 0;
233
                    break;
234
235
                // String quelconque (peut etre vide) -
236
                case 'text': -
237
                    return $checker && is_string($value); +
236
                case 'text': +
237
                    return $checker && is_string($value);
238
239
                // Adresse mail (255 caracteres max) -
240
                case 'mail': +
240
                case 'mail':
241
                    return $checker && is_string($value) && strlen($value) <= 50 && preg_match('/^[\w\.-]+@[\w\.-]+\.[a-z]{2,4}$/i', $value);
242
                    break;
243
                
244
                // Hash sha1 -
245
                case 'sha1': -
246
                    return $checker && is_string($value) && preg_match('/^[\da-f]{40}$/i', $value); +
245
                case 'sha1': +
246
                    return $checker && is_string($value) && preg_match('/^[\da-f]{40}$/i', $value);
247
                    break;
248
                
249
                default: @@ -559,7 +559,7 @@ Dead Code

- Generated by PHP_CodeCoverage 2.1.7 using PHP 5.6.11-1ubuntu3.1 and PHPUnit 4.7.6 at Mon Apr 18 8:26:51 UTC 2016. + Generated by PHP_CodeCoverage 2.1.7 using PHP 5.6.11-1ubuntu3.1 and PHPUnit 4.7.6 at Mon Apr 18 9:04:04 UTC 2016.

diff --git a/phpunit/coverage/ManagerError.php.html b/phpunit/coverage/ManagerError.php.html index 3951256..3745a17 100755 --- a/phpunit/coverage/ManagerError.php.html +++ b/phpunit/coverage/ManagerError.php.html @@ -247,7 +247,7 @@ Dead Code

- Generated by PHP_CodeCoverage 2.1.7 using PHP 5.6.11-1ubuntu3.1 and PHPUnit 4.7.6 at Mon Apr 18 8:26:51 UTC 2016. + Generated by PHP_CodeCoverage 2.1.7 using PHP 5.6.11-1ubuntu3.1 and PHPUnit 4.7.6 at Mon Apr 18 9:04:04 UTC 2016.

diff --git a/phpunit/coverage/ResourceDispatcher.php.html b/phpunit/coverage/ResourceDispatcher.php.html index 03af216..6a9a653 100755 --- a/phpunit/coverage/ResourceDispatcher.php.html +++ b/phpunit/coverage/ResourceDispatcher.php.html @@ -262,49 +262,49 @@
31
        *
32
        */
33
        public function __construct($url, $view=false){ -
34
            $this->error = ManagerError::Success; +
34
            $this->error = ManagerError::Success;
35
36
37
            /* [0] On met a jour la configuration
38
            =====================================================*/
39
            // Extensions supportees -
40
            $extensions_conf = json_decode( file_get_contents(__ROOT__.self::$extension_config_path), true ); +
40
            $extensions_conf = json_decode( file_get_contents(__ROOT__.self::$extension_config_path), true );
41
42
            // Gestion de l'erreur de parsage -
43
            if( $extensions_conf == null ){ +
43
            if( $extensions_conf == null ){
44
                $this->error = ManagerError::ParsingFailed;
45
                return false;
46
            }
47
-
48
            self::$supported_extensions = $extensions_conf; +
48
            self::$supported_extensions = $extensions_conf;
49
50
            // Dossiers supportes -
51
            $parents_conf = json_decode( file_get_contents(__ROOT__.self::$parents_config_path), true ); +
51
            $parents_conf = json_decode( file_get_contents(__ROOT__.self::$parents_config_path), true );
52
            
53
            // Gestion de l'erreur de parsage -
54
            if( $parents_conf == null ){ +
54
            if( $parents_conf == null ){
55
                $this->error = ManagerError::ParsingFailed;
56
                return false;
57
            }
58
-
59
            self::$supported_parents = $parents_conf; +
59
            self::$supported_parents = $parents_conf;
60
61
62
63
            /* [1] On recupere les donnees de l'URL
64
            ==================================================*/ -
65
            $serialFlags = array_slice( explode('/',$url), 1 ); +
65
            $serialFlags = array_slice( explode('/',$url), 1 );
66
67
            /* [2] On check/cree les drapeaux avec ces donnees
68
            ==================================================*/ -
69
            if( !$this->createFlags($serialFlags) ){ // Creation des drapeaux +
69
            if( !$this->createFlags($serialFlags) ){ // Creation des drapeaux
70
                $this->error = ManagerError::InvalidFlags;
71
                return false;
72
            }
73
74
            /* [3] On construit le chemin a partir des tags
75
            ==================================================*/ -
76
            if( !$this->buildPath() ){ // Construction du chemin +
76
            if( !$this->buildPath() ){ // Construction du chemin
77
                $this->error = ManagerError::UnreachableResource;
78
                return false;
79
            } @@ -312,10 +312,10 @@
81
            /* [4] On gere l'affichage pour l'appel externe/interne
82
            ==================================================*/
83
            if( $view ) // Appel externe -
84
                $this->view(); +
84
                $this->view();
85
86
             -
87
            return true; +
87
            return true;
88
89
        }
90
@@ -328,8 +328,8 @@
97
        *
98
        */
99
        public static function getResource($route){ -
100
            $instance = new ResourceDispatcher($route); -
101
            return $instance->getContent(); +
100
            $instance = new ResourceDispatcher($route); +
101
            return $instance->getContent();
102
        }
103
104
@@ -345,51 +345,51 @@
114
            /* [1] Verification des flags (version serialisee)
115
            ======================================================*/
116
-
117
            $correct = true; +
117
            $correct = true;
118
119
            // Verification du nombre de drapeaux () au moins 3 -
120
            $correct = $correct && count($serialFlags) >= 3; +
120
            $correct = $correct && count($serialFlags) >= 3;
121
122
            // Verification que l'extension est correcte -
123
            $correct = $correct && array_key_exists($serialFlags[0], self::$supported_extensions); +
123
            $correct = $correct && array_key_exists($serialFlags[0], self::$supported_extensions);
124
125
            // Verification du filename -
126
            $correct = $correct && preg_match('/^[\w_\.-]+$/i', $serialFlags[1]); +
126
            $correct = $correct && preg_match('/^[\w_\.-]+$/i', $serialFlags[1]);
127
128
            // Verification du parent -
129
            $correct = $correct && array_key_exists($serialFlags[2], self::$supported_parents); +
129
            $correct = $correct && array_key_exists($serialFlags[2], self::$supported_parents);
130
131
            // Verification du sous-parent (optionnel) -
132
            $opt_subParent = count($serialFlags) >= 4; +
132
            $opt_subParent = count($serialFlags) >= 4;
133
134
            if( $opt_subParent ) -
135
                $correct = $correct && preg_match('/^[\w_-]+$/i', $serialFlags[3]); +
135
                $correct = $correct && preg_match('/^[\w_-]+$/i', $serialFlags[3]);
136
137
            // Verification de la couleur (optionnel) -
138
            $opt_color = count($serialFlags) >= 5 && preg_match('/^[\da-f]{6,8}+$/i', $serialFlags[4]); +
138
            $opt_color = count($serialFlags) >= 5 && preg_match('/^[\da-f]{6,8}+$/i', $serialFlags[4]);
139
-
140
            if( !$correct ) -
141
                return false; +
140
            if( !$correct ) +
141
                return false;
142
143
                
144
            /* [2] Creation (non serialisee) des flags
145
            ======================================================*/
146
            // Si tout se deroule bien, on cree les flags -
147
            $this->flags = array( -
148
                'extension' => $serialFlags[0], -
149
                'filename'  => $serialFlags[1], -
150
                'parent'    => $serialFlags[2] -
151
            ); +
147
            $this->flags = array( +
148
                'extension' => $serialFlags[0], +
149
                'filename'  => $serialFlags[1], +
150
                'parent'    => $serialFlags[2] +
151
            );
152
153
            // Ajout du sous-parent optionnel
154
            if( $opt_subParent ) -
155
                $this->flags['subparent'] = $serialFlags[3]; +
155
                $this->flags['subparent'] = $serialFlags[3];
156
157
            // Ajout du color optionnel
158
            if( $opt_color ) -
159
                $this->flags['color'] = '#'.$serialFlags[4]; +
159
                $this->flags['color'] = '#'.$serialFlags[4];
160
-
161
            return true; +
161
            return true;
162
163
164
        } @@ -408,10 +408,10 @@
177
            /* [1] On recupere le HEADER associe a l'extension
178
            ==========================================================*/
179
            // Si aucun header pour cet cle, on retourne une erreur -
180
            if( !isset(self::$supported_extensions[$this->flags['extension']]) ) return false; +
180
            if( !isset(self::$supported_extensions[$this->flags['extension']]) ) return false;
181
182
            // On recupere le header associe -
183
            $header = self::$supported_extensions[$this->flags['extension']]; +
183
            $header = self::$supported_extensions[$this->flags['extension']];
184
185
186
@@ -420,23 +420,23 @@
189
            /* [2] On recupere le chemin associe au parent
190
            ==========================================================*/
191
            // Si aucun dossier pour cet indice, on retourne une erreur -
192
            if( !isset(self::$supported_parents[$this->flags['parent']]) ) return false; +
192
            if( !isset(self::$supported_parents[$this->flags['parent']]) ) return false;
193
194
            // On recupere le dossier associe -
195
            $parent = self::$supported_parents[$this->flags['parent']]; +
195
            $parent = self::$supported_parents[$this->flags['parent']];
196
197
198
            /* [3] Gestion du sous-parent optionnel
199
            ==========================================================*/ -
200
            $opt_subParent = (isset($this->flags['subparent'])) ? $this->flags['subparent'].'/' : ''; +
200
            $opt_subParent = (isset($this->flags['subparent'])) ? $this->flags['subparent'].'/' : '';
201
202
203
            /* [4] Gestion du color optionnel
204
            =========================================================*/ -
205
            $this->stylesheet = ""; +
205
            $this->stylesheet = "";
206
207
            // si le color est defini -
208
            if( isset($this->flags['color']) ){ +
208
            if( isset($this->flags['color']) ){
209
                $this->stylesheet = "\n<style type='text/css'>\n";
210
                    $this->stylesheet .= "\t#stylisable{\n";
211
                        $this->stylesheet .= "\t\tfill: ".$this->flags['color']." !important;\n"; @@ -449,15 +449,15 @@
218
219
            /* [5] On definit le header
220
            ==========================================================*/ -
221
            $this->header = $header; +
221
            $this->header = $header;
222
223
            /* [6] On construit le chemin 
224
            ==========================================================*/ -
225
            $this->path = __ROOT__.$parent.'/'.$opt_subParent.$this->flags['filename'].'.'.$this->flags['extension']; +
225
            $this->path = __ROOT__.$parent.'/'.$opt_subParent.$this->flags['filename'].'.'.$this->flags['extension'];
226
227
            /* [7] On retourne si le fichier existe ou non
228
            ==========================================================*/ -
229
            return @file_get_contents( $this->path ) != false; +
229
            return @file_get_contents( $this->path ) != false;
230
231
        }
232
@@ -489,15 +489,15 @@
258
        */
259
        public function getContent(){
260
            // S'il y a eu une erreur en amont -
261
            if( $this->error != ManagerError::Success ) -
262
                return false; // on retourne faux +
261
            if( $this->error != ManagerError::Success ) +
262
                return false; // on retourne faux
263
264
265
            // On inclut le contenu -
266
            $content = file_get_contents($this->path); +
266
            $content = file_get_contents($this->path);
267
268
            // On retourne tout -
269
            return str_replace( '</svg>', $this->stylesheet.'</svg>', $content ); +
269
            return str_replace( '</svg>', $this->stylesheet.'</svg>', $content );
270
        }
271
272
@@ -517,7 +517,7 @@ Dead Code

- Generated by PHP_CodeCoverage 2.1.7 using PHP 5.6.11-1ubuntu3.1 and PHPUnit 4.7.6 at Mon Apr 18 8:26:51 UTC 2016. + Generated by PHP_CodeCoverage 2.1.7 using PHP 5.6.11-1ubuntu3.1 and PHPUnit 4.7.6 at Mon Apr 18 9:04:04 UTC 2016.

diff --git a/phpunit/coverage/autoloader.php.html b/phpunit/coverage/autoloader.php.html index 074336c..725a46a 100755 --- a/phpunit/coverage/autoloader.php.html +++ b/phpunit/coverage/autoloader.php.html @@ -167,19 +167,19 @@
27
    *
28
    */
29
    function autoloader($className){ -
30
        $path = ''; +
30
        $path = '';
31
32
        /* [1] On utilise le namespace pour localiser
33
        ===============================================*/
34
        // On remplace les '\' par des '/' -
35
        $path = str_replace('\\', '/', $className) . '.php'; -
36
        $path = __ROOT__.'/'.$path; +
35
        $path = str_replace('\\', '/', $className) . '.php'; +
36
        $path = __ROOT__.'/'.$path;
37
38
        // Si le fichier existe -
39
        if( file_exists($path) ) -
40
            require_once $path; // on inclue le fichier +
39
        if( file_exists($path) ) +
40
            require_once $path; // on inclue le fichier
41
-
42
    } +
42
    }
43
    
44
    // On definit l'autoloader comme autoloader (obvious)
45
    spl_autoload_register('autoloader', false, true); @@ -214,7 +214,7 @@ Dead Code

- Generated by PHP_CodeCoverage 2.1.7 using PHP 5.6.11-1ubuntu3.1 and PHPUnit 4.7.6 at Mon Apr 18 8:26:51 UTC 2016. + Generated by PHP_CodeCoverage 2.1.7 using PHP 5.6.11-1ubuntu3.1 and PHPUnit 4.7.6 at Mon Apr 18 9:04:04 UTC 2016.

diff --git a/phpunit/coverage/index.html b/phpunit/coverage/index.html index ebe8e60..0981eb5 100755 --- a/phpunit/coverage/index.html +++ b/phpunit/coverage/index.html @@ -43,21 +43,21 @@ Total
-
- 63.81% covered (warning) +
+ 66.21% covered (warning)
-
63.81%
-
231 / 362
+
66.21%
+
241 / 364
-
- 36.11% covered (danger) +
+ 44.44% covered (danger)
-
36.11%
-
13 / 36
+
44.44%
+
16 / 36
14.29% covered (danger) @@ -71,21 +71,21 @@ repo
-
- 13.95% covered (danger) +
+ 16.28% covered (danger)
-
13.95%
-
6 / 43
+
16.28%
+
7 / 43
-
- 0.00% covered (danger) +
+ 20.00% covered (danger)
-
0.00%
-
0 / 5
+
20.00%
+
1 / 5
0.00% covered (danger) @@ -155,21 +155,21 @@ ModuleRequest.php
-
- 68.60% covered (warning) +
+ 77.27% covered (warning)
-
68.60%
-
59 / 86
+
77.27%
+
68 / 88
-
- 25.00% covered (danger) +
+ 50.00% covered (danger)
-
25.00%
-
2 / 8
+
50.00%
+
4 / 8
0.00% covered (danger) @@ -294,7 +294,7 @@ High: 90% to 100%

- Generated by PHP_CodeCoverage 2.1.7 using PHP 5.6.11-1ubuntu3.1 and PHPUnit 4.7.6 at Mon Apr 18 8:26:51 UTC 2016. + Generated by PHP_CodeCoverage 2.1.7 using PHP 5.6.11-1ubuntu3.1 and PHPUnit 4.7.6 at Mon Apr 18 9:04:04 UTC 2016.

diff --git a/phpunit/coverage/sessionManager.php.html b/phpunit/coverage/sessionManager.php.html index bceb5a7..2242773 100755 --- a/phpunit/coverage/sessionManager.php.html +++ b/phpunit/coverage/sessionManager.php.html @@ -315,7 +315,7 @@ Dead Code

- Generated by PHP_CodeCoverage 2.1.7 using PHP 5.6.11-1ubuntu3.1 and PHPUnit 4.7.6 at Mon Apr 18 8:26:51 UTC 2016. + Generated by PHP_CodeCoverage 2.1.7 using PHP 5.6.11-1ubuntu3.1 and PHPUnit 4.7.6 at Mon Apr 18 9:04:04 UTC 2016.

diff --git a/phpunit/tests/ModuleRequest.php b/phpunit/tests/ModuleRequest.php index 24022bb..f725ee5 100644 --- a/phpunit/tests/ModuleRequest.php +++ b/phpunit/tests/ModuleRequest.php @@ -82,16 +82,67 @@ $postdata = array( 'path' => 'module/method' ); $req = \manager\ModuleRequest::fromPost( $postdata ); - $this->assertEquals( $req->error, \manager\ManagerError::TokenError ); + $this->assertEquals( $req->error, \manager\ManagerError::PermissionError ); } - public function testConstructInvalidToken(){ + public function testConstructInvalidTokenType(){ + $_SERVER['PHP_AUTH_DIGEST'] = str_repeat('f', 10); + $postdata = array( 'path' => 'module/method' ); + + $req = \manager\ModuleRequest::fromPost( $postdata ); + $this->assertEquals( $req->error, \manager\ManagerError::PermissionError ); + } + public function testConstructInvalidTokenValue(){ $_SERVER['PHP_AUTH_DIGEST'] = str_repeat('f', 40); - $_SESSION['permission'] = array(); $postdata = array( 'path' => 'module/method' ); $req = \manager\ModuleRequest::fromPost( $postdata ); $this->assertEquals( $req->error, \manager\ManagerError::TokenError ); } + public function testConstructValidTokenInBdd(){ + $_SERVER['PHP_AUTH_DIGEST'] = '52945efbed43b50c12413f2f0e9519bfd9e98ce8'; + $postdata = array( 'path' => 'module/method' ); + + $req = \manager\ModuleRequest::fromPost( $postdata ); + $this->assertEquals( $req->error, \manager\ManagerError::Success ); + } + + /* (3) Gestion des paramètres */ + public function testConstructNoParamRequired(){ + $_SESSION['permission'] = array(); + + $req = new \manager\ModuleRequest( 'module/method', array('useless') ); + $this->assertEquals( $req->error, \manager\ManagerError::Success ); + } + public function testConstructMissingParam(){ + $_SESSION['permission'] = array(); + + $req = new \manager\ModuleRequest( 'module/phpunitParams', array() ); + $this->assertEquals( $req->error, \manager\ManagerError::ParamError ); + } + public function testConstructWrongParamType(){ + $_SESSION['permission'] = array(); + + $params = array( 'p1' => 'sometext', 'p2' => 'sometext' ); + + $req = new \manager\ModuleRequest( 'module/phpunitParams', $params ); + $this->assertEquals( $req->error, \manager\ManagerError::ParamError ); + } + public function testConstructWrongParamTypeOther(){ + $_SESSION['permission'] = array(); + + $params = array( 'p1' => 10, 'p2' => 'sometext' ); + + $req = new \manager\ModuleRequest( 'module/phpunitParams', $params ); + $this->assertEquals( $req->error, \manager\ManagerError::ParamError ); + } + public function testConstructCorrectParams(){ + $_SESSION['permission'] = array(); + + $params = array( 'p1' => 'sometext', 'p2' => 10 ); + + $req = new \manager\ModuleRequest( 'module/phpunitParams', $params ); + $this->assertEquals( $req->error, \manager\ManagerError::Success ); + } } diff --git a/tags b/tags new file mode 100644 index 0000000..22574f4 --- /dev/null +++ b/tags @@ -0,0 +1,3999 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ +!_TAG_PROGRAM_NAME Exuberant Ctags // +!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ +!_TAG_PROGRAM_VERSION 5.9~svn20110310 // +$ js/lib/reset.js /^function $(idOrClass){$/;" f +$.$.$.$ phpunit/coverage/js/bootstrap.min.js /^if(typeof jQuery==="undefined"){throw new Error("Bootstrap's JavaScript requires jQuery")}+function($){"use strict";var version=$.fn.jquery.split(" ")[0].split(".");if(version[0]<2&&version[1]<9||version[0]==1&&version[1]==9&&version[2]<1){throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}}(jQuery);+function($){"use strict";function transitionEnd(){var el=document.createElement("bootstrap");var transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var name in transEndEventNames){if(el.style[name]!==undefined){return{end:transEndEventNames[name]}}}return false}$.fn.emulateTransitionEnd=function(duration){var called=false;var $el=this;$(this).one("bsTransitionEnd",function(){called=true});var callback=function(){if(!called)$($el).trigger($.support.transition.end)};setTimeout(callback,duration);return this};$(function(){$.support.transition=transitionEnd();if(!$.support.transition)return;$.event.special.bsTransitionEnd={bindType:$.support.transition.end,delegateType:$.support.transition.end,handle:function(e){if($(e.target).is(this))return e.handleObj.handler.apply(this,arguments)}}})}(jQuery);+function($){"use strict";var dismiss='[data-dismiss="alert"]';var Alert=function(el){$(el).on("click",dismiss,this.close)};Alert.VERSION="3.3.5";Alert.TRANSITION_DURATION=150;Alert.prototype.close=function(e){var $this=$(this);var selector=$this.attr("data-target");if(!selector){selector=$this.attr("href");selector=selector&&selector.replace(\/.*(?=#[^\\s]*$)\/,"")}var $parent=$(selector);if(e)e.preventDefault();if(!$parent.length){$parent=$this.closest(".alert")}$parent.trigger(e=$.Event("close.bs.alert"));if(e.isDefaultPrevented())return;$parent.removeClass("in");function removeElement(){$parent.detach().trigger("closed.bs.alert").remove()}$.support.transition&&$parent.hasClass("fade")?$parent.one("bsTransitionEnd",removeElement).emulateTransitionEnd(Alert.TRANSITION_DURATION):removeElement()};function Plugin(option){return this.each(function(){var $this=$(this);var data=$this.data("bs.alert");if(!data)$this.data("bs.alert",data=new Alert(this));if(typeof option=="string")data[option].call($this)})}var old=$.fn.alert;$.fn.alert=Plugin;$.fn.alert.Constructor=Alert;$.fn.alert.noConflict=function(){$.fn.alert=old;return this};$(document).on("click.bs.alert.data-api",dismiss,Alert.prototype.close)}(jQuery);+function($){"use strict";var Button=function(element,options){this.$element=$(element);this.options=$.extend({},Button.DEFAULTS,options);this.isLoading=false};Button.VERSION="3.3.5";Button.DEFAULTS={loadingText:"loading..."};Button.prototype.setState=function(state){var d="disabled";var $el=this.$element;var val=$el.is("input")?"val":"html";var data=$el.data();state+="Text";if(data.resetText==null)$el.data("resetText",$el[val]());setTimeout($.proxy(function(){$el[val](data[state]==null?this.options[state]:data[state]);if(state=="loadingText"){this.isLoading=true;$el.addClass(d).attr(d,d)}else if(this.isLoading){this.isLoading=false;$el.removeClass(d).removeAttr(d)}},this),0)};Button.prototype.toggle=function(){var changed=true;var $parent=this.$element.closest('[data-toggle="buttons"]');if($parent.length){var $input=this.$element.find("input");if($input.prop("type")=="radio"){if($input.prop("checked"))changed=false;$parent.find(".active").removeClass("active");this.$element.addClass("active")}else if($input.prop("type")=="checkbox"){if($input.prop("checked")!==this.$element.hasClass("active"))changed=false;this.$element.toggleClass("active")}$input.prop("checked",this.$element.hasClass("active"));if(changed)$input.trigger("change")}else{this.$element.attr("aria-pressed",!this.$element.hasClass("active"));this.$element.toggleClass("active")}};function Plugin(option){return this.each(function(){var $this=$(this);var data=$this.data("bs.button");var options=typeof option=="object"&&option;if(!data)$this.data("bs.button",data=new Button(this,options));if(option=="toggle")data.toggle();else if(option)data.setState(option)})}var old=$.fn.button;$.fn.button=Plugin;$.fn.button.Constructor=Button;$.fn.button.noConflict=function(){$.fn.button=old;return this};$(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(e){var $btn=$(e.target);if(!$btn.hasClass("btn"))$btn=$btn.closest(".btn");Plugin.call($btn,"toggle");if(!($(e.target).is('input[type="radio"]')||$(e.target).is('input[type="checkbox"]')))e.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(e){$(e.target).closest(".btn").toggleClass("focus",\/^focus(in)?$\/.test(e.type))})}(jQuery);+function($){"use strict";var Carousel=function(element,options){this.$element=$(element);this.$indicators=this.$element.find(".carousel-indicators");this.options=options;this.paused=null;this.sliding=null;this.interval=null;this.$active=null;this.$items=null;this.options.keyboard&&this.$element.on("keydown.bs.carousel",$.proxy(this.keydown,this));this.options.pause=="hover"&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",$.proxy(this.pause,this)).on("mouseleave.bs.carousel",$.proxy(this.cycle,this))};Carousel.VERSION="3.3.5";Carousel.TRANSITION_DURATION=600;Carousel.DEFAULTS={interval:5e3,pause:"hover",wrap:true,keyboard:true};Carousel.prototype.keydown=function(e){if(\/input|textarea\/i.test(e.target.tagName))return;switch(e.which){case 37:this.prev();break;case 39:this.next();break;default:return}e.preventDefault()};Carousel.prototype.cycle=function(e){e||(this.paused=false);this.interval&&clearInterval(this.interval);this.options.interval&&!this.paused&&(this.interval=setInterval($.proxy(this.next,this),this.options.interval));return this};Carousel.prototype.getItemIndex=function(item){this.$items=item.parent().children(".item");return this.$items.index(item||this.$active)};Carousel.prototype.getItemForDirection=function(direction,active){var activeIndex=this.getItemIndex(active);var willWrap=direction=="prev"&&activeIndex===0||direction=="next"&&activeIndex==this.$items.length-1;if(willWrap&&!this.options.wrap)return active;var delta=direction=="prev"?-1:1;var itemIndex=(activeIndex+delta)%this.$items.length;return this.$items.eq(itemIndex)};Carousel.prototype.to=function(pos){var that=this;var activeIndex=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(pos>this.$items.length-1||pos<0)return;if(this.sliding)return this.$element.one("slid.bs.carousel",function(){that.to(pos)});if(activeIndex==pos)return this.pause().cycle();return this.slide(pos>activeIndex?"next":"prev",this.$items.eq(pos))};Carousel.prototype.pause=function(e){e||(this.paused=true);if(this.$element.find(".next, .prev").length&&$.support.transition){this.$element.trigger($.support.transition.end);this.cycle(true)}this.interval=clearInterval(this.interval);return this};Carousel.prototype.next=function(){if(this.sliding)return;return this.slide("next")};Carousel.prototype.prev=function(){if(this.sliding)return;return this.slide("prev")};Carousel.prototype.slide=function(type,next){var $active=this.$element.find(".item.active");var $next=next||this.getItemForDirection(type,$active);var isCycling=this.interval;var direction=type=="next"?"left":"right";var that=this;if($next.hasClass("active"))return this.sliding=false;var relatedTarget=$next[0];var slideEvent=$.Event("slide.bs.carousel",{relatedTarget:relatedTarget,direction:direction});this.$element.trigger(slideEvent);if(slideEvent.isDefaultPrevented())return;this.sliding=true;isCycling&&this.pause();if(this.$indicators.length){this.$indicators.find(".active").removeClass("active");var $nextIndicator=$(this.$indicators.children()[this.getItemIndex($next)]);$nextIndicator&&$nextIndicator.addClass("active")}var slidEvent=$.Event("slid.bs.carousel",{relatedTarget:relatedTarget,direction:direction});if($.support.transition&&this.$element.hasClass("slide")){$next.addClass(type);$next[0].offsetWidth;$active.addClass(direction);$next.addClass(direction);$active.one("bsTransitionEnd",function(){$next.removeClass([type,direction].join(" ")).addClass("active");$active.removeClass(["active",direction].join(" "));that.sliding=false;setTimeout(function(){that.$element.trigger(slidEvent)},0)}).emulateTransitionEnd(Carousel.TRANSITION_DURATION)}else{$active.removeClass("active");$next.addClass("active");this.sliding=false;this.$element.trigger(slidEvent)}isCycling&&this.cycle();return this};function Plugin(option){return this.each(function(){var $this=$(this);var data=$this.data("bs.carousel");var options=$.extend({},Carousel.DEFAULTS,$this.data(),typeof option=="object"&&option);var action=typeof option=="string"?option:options.slide;if(!data)$this.data("bs.carousel",data=new Carousel(this,options));if(typeof option=="number")data.to(option);else if(action)data[action]();else if(options.interval)data.pause().cycle()})}var old=$.fn.carousel;$.fn.carousel=Plugin;$.fn.carousel.Constructor=Carousel;$.fn.carousel.noConflict=function(){$.fn.carousel=old;return this};var clickHandler=function(e){var href;var $this=$(this);var $target=$($this.attr("data-target")||(href=$this.attr("href"))&&href.replace(\/.*(?=#[^\\s]+$)\/,""));if(!$target.hasClass("carousel"))return;var options=$.extend({},$target.data(),$this.data());var slideIndex=$this.attr("data-slide-to");if(slideIndex)options.interval=false;Plugin.call($target,options);if(slideIndex){$target.data("bs.carousel").to(slideIndex)}e.preventDefault()};$(document).on("click.bs.carousel.data-api","[data-slide]",clickHandler).on("click.bs.carousel.data-api","[data-slide-to]",clickHandler);$(window).on("load",function(){$('[data-ride="carousel"]').each(function(){var $carousel=$(this);Plugin.call($carousel,$carousel.data())})})}(jQuery);+function($){"use strict";var Collapse=function(element,options){this.$element=$(element);this.options=$.extend({},Collapse.DEFAULTS,options);this.$trigger=$('[data-toggle="collapse"][href="#'+element.id+'"],'+'[data-toggle="collapse"][data-target="#'+element.id+'"]');this.transitioning=null;if(this.options.parent){this.$parent=this.getParent()}else{this.addAriaAndCollapsedClass(this.$element,this.$trigger)}if(this.options.toggle)this.toggle()};Collapse.VERSION="3.3.5";Collapse.TRANSITION_DURATION=350;Collapse.DEFAULTS={toggle:true};Collapse.prototype.dimension=function(){var hasWidth=this.$element.hasClass("width");return hasWidth?"width":"height"};Collapse.prototype.show=function(){if(this.transitioning||this.$element.hasClass("in"))return;var activesData;var actives=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(actives&&actives.length){activesData=actives.data("bs.collapse");if(activesData&&activesData.transitioning)return}var startEvent=$.Event("show.bs.collapse");this.$element.trigger(startEvent);if(startEvent.isDefaultPrevented())return;if(actives&&actives.length){Plugin.call(actives,"hide");activesData||actives.data("bs.collapse",null)}var dimension=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[dimension](0).attr("aria-expanded",true);this.$trigger.removeClass("collapsed").attr("aria-expanded",true);this.transitioning=1;var complete=function(){this.$element.removeClass("collapsing").addClass("collapse in")[dimension]("");this.transitioning=0;this.$element.trigger("shown.bs.collapse")};if(!$.support.transition)return complete.call(this);var scrollSize=$.camelCase(["scroll",dimension].join("-"));this.$element.one("bsTransitionEnd",$.proxy(complete,this)).emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])};Collapse.prototype.hide=function(){if(this.transitioning||!this.$element.hasClass("in"))return;var startEvent=$.Event("hide.bs.collapse");this.$element.trigger(startEvent);if(startEvent.isDefaultPrevented())return;var dimension=this.dimension();this.$element[dimension](this.$element[dimension]())[0].offsetHeight;this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",false);this.$trigger.addClass("collapsed").attr("aria-expanded",false);this.transitioning=1;var complete=function(){this.transitioning=0;this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};if(!$.support.transition)return complete.call(this);this.$element[dimension](0).one("bsTransitionEnd",$.proxy(complete,this)).emulateTransitionEnd(Collapse.TRANSITION_DURATION)};Collapse.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};Collapse.prototype.getParent=function(){return $(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each($.proxy(function(i,element){var $element=$(element);this.addAriaAndCollapsedClass(getTargetFromTrigger($element),$element)},this)).end()};Collapse.prototype.addAriaAndCollapsedClass=function($element,$trigger){var isOpen=$element.hasClass("in");$element.attr("aria-expanded",isOpen);$trigger.toggleClass("collapsed",!isOpen).attr("aria-expanded",isOpen)};function getTargetFromTrigger($trigger){var href;var target=$trigger.attr("data-target")||(href=$trigger.attr("href"))&&href.replace(\/.*(?=#[^\\s]+$)\/,"");return $(target)}function Plugin(option){return this.each(function(){var $this=$(this);var data=$this.data("bs.collapse");var options=$.extend({},Collapse.DEFAULTS,$this.data(),typeof option=="object"&&option);if(!data&&options.toggle&&\/show|hide\/.test(option))options.toggle=false;if(!data)$this.data("bs.collapse",data=new Collapse(this,options));if(typeof option=="string")data[option]()})}var old=$.fn.collapse;$.fn.collapse=Plugin;$.fn.collapse.Constructor=Collapse;$.fn.collapse.noConflict=function(){$.fn.collapse=old;return this};$(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(e){var $this=$(this);if(!$this.attr("data-target"))e.preventDefault();var $target=getTargetFromTrigger($this);var data=$target.data("bs.collapse");var option=data?"toggle":$this.data();Plugin.call($target,option)})}(jQuery);+function($){"use strict";var backdrop=".dropdown-backdrop";var toggle='[data-toggle="dropdown"]';var Dropdown=function(element){$(element).on("click.bs.dropdown",this.toggle)};Dropdown.VERSION="3.3.5";function getParent($this){var selector=$this.attr("data-target");if(!selector){selector=$this.attr("href");selector=selector&&\/#[A-Za-z]\/.test(selector)&&selector.replace(\/.*(?=#[^\\s]*$)\/,"")}var $parent=selector&&$(selector);return $parent&&$parent.length?$parent:$this.parent()}function clearMenus(e){if(e&&e.which===3)return;$(backdrop).remove();$(toggle).each(function(){var $this=$(this);var $parent=getParent($this);var relatedTarget={relatedTarget:this};if(!$parent.hasClass("open"))return;if(e&&e.type=="click"&&\/input|textarea\/i.test(e.target.tagName)&&$.contains($parent[0],e.target))return;$parent.trigger(e=$.Event("hide.bs.dropdown",relatedTarget));if(e.isDefaultPrevented())return;$this.attr("aria-expanded","false");$parent.removeClass("open").trigger("hidden.bs.dropdown",relatedTarget)})}Dropdown.prototype.toggle=function(e){var $this=$(this);if($this.is(".disabled, :disabled"))return;var $parent=getParent($this);var isActive=$parent.hasClass("open");clearMenus();if(!isActive){if("ontouchstart"in document.documentElement&&!$parent.closest(".navbar-nav").length){$(document.createElement("div")).addClass("dropdown-backdrop").insertAfter($(this)).on("click",clearMenus)}var relatedTarget={relatedTarget:this};$parent.trigger(e=$.Event("show.bs.dropdown",relatedTarget));if(e.isDefaultPrevented())return;$this.trigger("focus").attr("aria-expanded","true");$parent.toggleClass("open").trigger("shown.bs.dropdown",relatedTarget)}return false};Dropdown.prototype.keydown=function(e){if(!\/(38|40|27|32)\/.test(e.which)||\/input|textarea\/i.test(e.target.tagName))return;var $this=$(this);e.preventDefault();e.stopPropagation();if($this.is(".disabled, :disabled"))return;var $parent=getParent($this);var isActive=$parent.hasClass("open");if(!isActive&&e.which!=27||isActive&&e.which==27){if(e.which==27)$parent.find(toggle).trigger("focus");return $this.trigger("click")}var desc=" li:not(.disabled):visible a";var $items=$parent.find(".dropdown-menu"+desc);if(!$items.length)return;var index=$items.index(e.target);if(e.which==38&&index>0)index--;if(e.which==40&&index<$items.length-1)index++;if(!~index)index=0;$items.eq(index).trigger("focus")};function Plugin(option){return this.each(function(){var $this=$(this);var data=$this.data("bs.dropdown");if(!data)$this.data("bs.dropdown",data=new Dropdown(this));if(typeof option=="string")data[option].call($this)})}var old=$.fn.dropdown;$.fn.dropdown=Plugin;$.fn.dropdown.Constructor=Dropdown;$.fn.dropdown.noConflict=function(){$.fn.dropdown=old;return this};$(document).on("click.bs.dropdown.data-api",clearMenus).on("click.bs.dropdown.data-api",".dropdown form",function(e){e.stopPropagation()}).on("click.bs.dropdown.data-api",toggle,Dropdown.prototype.toggle).on("keydown.bs.dropdown.data-api",toggle,Dropdown.prototype.keydown).on("keydown.bs.dropdown.data-api",".dropdown-menu",Dropdown.prototype.keydown)}(jQuery);+function($){"use strict";var Modal=function(element,options){this.options=options;this.$body=$(document.body);this.$element=$(element);this.$dialog=this.$element.find(".modal-dialog");this.$backdrop=null;this.isShown=null;this.originalBodyPad=null;this.scrollbarWidth=0;this.ignoreBackdropClick=false;if(this.options.remote){this.$element.find(".modal-content").load(this.options.remote,$.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))}};Modal.VERSION="3.3.5";Modal.TRANSITION_DURATION=300;Modal.BACKDROP_TRANSITION_DURATION=150;Modal.DEFAULTS={backdrop:true,keyboard:true,show:true};Modal.prototype.toggle=function(_relatedTarget){return this.isShown?this.hide():this.show(_relatedTarget)};Modal.prototype.show=function(_relatedTarget){var that=this;var e=$.Event("show.bs.modal",{relatedTarget:_relatedTarget});this.$element.trigger(e);if(this.isShown||e.isDefaultPrevented())return;this.isShown=true;this.checkScrollbar();this.setScrollbar();this.$body.addClass("modal-open");this.escape();this.resize();this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',$.proxy(this.hide,this));this.$dialog.on("mousedown.dismiss.bs.modal",function(){that.$element.one("mouseup.dismiss.bs.modal",function(e){if($(e.target).is(that.$element))that.ignoreBackdropClick=true})});this.backdrop(function(){var transition=$.support.transition&&that.$element.hasClass("fade");if(!that.$element.parent().length){that.$element.appendTo(that.$body)}that.$element.show().scrollTop(0);that.adjustDialog();if(transition){that.$element[0].offsetWidth}that.$element.addClass("in");that.enforceFocus();var e=$.Event("shown.bs.modal",{relatedTarget:_relatedTarget});transition?that.$dialog.one("bsTransitionEnd",function(){that.$element.trigger("focus").trigger(e)}).emulateTransitionEnd(Modal.TRANSITION_DURATION):that.$element.trigger("focus").trigger(e)})};Modal.prototype.hide=function(e){if(e)e.preventDefault();e=$.Event("hide.bs.modal");this.$element.trigger(e);if(!this.isShown||e.isDefaultPrevented())return;this.isShown=false;this.escape();this.resize();$(document).off("focusin.bs.modal");this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal");this.$dialog.off("mousedown.dismiss.bs.modal");$.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",$.proxy(this.hideModal,this)).emulateTransitionEnd(Modal.TRANSITION_DURATION):this.hideModal()};Modal.prototype.enforceFocus=function(){$(document).off("focusin.bs.modal").on("focusin.bs.modal",$.proxy(function(e){if(this.$element[0]!==e.target&&!this.$element.has(e.target).length){this.$element.trigger("focus")}},this))};Modal.prototype.escape=function(){if(this.isShown&&this.options.keyboard){this.$element.on("keydown.dismiss.bs.modal",$.proxy(function(e){e.which==27&&this.hide()},this))}else if(!this.isShown){this.$element.off("keydown.dismiss.bs.modal")}};Modal.prototype.resize=function(){if(this.isShown){$(window).on("resize.bs.modal",$.proxy(this.handleUpdate,this))}else{$(window).off("resize.bs.modal")}};Modal.prototype.hideModal=function(){var that=this;this.$element.hide();this.backdrop(function(){that.$body.removeClass("modal-open");that.resetAdjustments();that.resetScrollbar();that.$element.trigger("hidden.bs.modal")})};Modal.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove();this.$backdrop=null};Modal.prototype.backdrop=function(callback){var that=this;var animate=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var doAnimate=$.support.transition&&animate;this.$backdrop=$(document.createElement("div")).addClass("modal-backdrop "+animate).appendTo(this.$body);this.$element.on("click.dismiss.bs.modal",$.proxy(function(e){if(this.ignoreBackdropClick){this.ignoreBackdropClick=false;return}if(e.target!==e.currentTarget)return;this.options.backdrop=="static"?this.$element[0].focus():this.hide()},this));if(doAnimate)this.$backdrop[0].offsetWidth;this.$backdrop.addClass("in");if(!callback)return;doAnimate?this.$backdrop.one("bsTransitionEnd",callback).emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION):callback()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var callbackRemove=function(){that.removeBackdrop();callback&&callback()};$.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",callbackRemove).emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION):callbackRemove()}else if(callback){callback()}};Modal.prototype.handleUpdate=function(){this.adjustDialog()};Modal.prototype.adjustDialog=function(){var modalIsOverflowing=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&modalIsOverflowing?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!modalIsOverflowing?this.scrollbarWidth:""})};Modal.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})};Modal.prototype.checkScrollbar=function(){var fullWindowWidth=window.innerWidth;if(!fullWindowWidth){var documentElementRect=document.documentElement.getBoundingClientRect();fullWindowWidth=documentElementRect.right-Math.abs(documentElementRect.left)}this.bodyIsOverflowing=document.body.clientWidth
<\/div>
<\/div><\/div>',trigger:"hover focus",title:"",delay:0,html:false,container:false,viewport:{selector:"body",padding:0}};Tooltip.prototype.init=function(type,element,options){this.enabled=true;this.type=type;this.$element=$(element);this.options=this.getOptions(options);this.$viewport=this.options.viewport&&$($.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport);this.inState={click:false,hover:false,focus:false};if(this.$element[0]instanceof document.constructor&&!this.options.selector){throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!")}var triggers=this.options.trigger.split(" ");for(var i=triggers.length;i--;){var trigger=triggers[i];if(trigger=="click"){this.$element.on("click."+this.type,this.options.selector,$.proxy(this.toggle,this))}else if(trigger!="manual"){var eventIn=trigger=="hover"?"mouseenter":"focusin";var eventOut=trigger=="hover"?"mouseleave":"focusout";this.$element.on(eventIn+"."+this.type,this.options.selector,$.proxy(this.enter,this));this.$element.on(eventOut+"."+this.type,this.options.selector,$.proxy(this.leave,this))}}this.options.selector?this._options=$.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()};Tooltip.prototype.getDefaults=function(){return Tooltip.DEFAULTS};Tooltip.prototype.getOptions=function(options){options=$.extend({},this.getDefaults(),this.$element.data(),options);if(options.delay&&typeof options.delay=="number"){options.delay={show:options.delay,hide:options.delay}}return options};Tooltip.prototype.getDelegateOptions=function(){var options={};var defaults=this.getDefaults();this._options&&$.each(this._options,function(key,value){if(defaults[key]!=value)options[key]=value});return options};Tooltip.prototype.enter=function(obj){var self=obj instanceof this.constructor?obj:$(obj.currentTarget).data("bs."+this.type);if(!self){self=new this.constructor(obj.currentTarget,this.getDelegateOptions());$(obj.currentTarget).data("bs."+this.type,self)}if(obj instanceof $.Event){self.inState[obj.type=="focusin"?"focus":"hover"]=true}if(self.tip().hasClass("in")||self.hoverState=="in"){self.hoverState="in";return}clearTimeout(self.timeout);self.hoverState="in";if(!self.options.delay||!self.options.delay.show)return self.show();self.timeout=setTimeout(function(){if(self.hoverState=="in")self.show()},self.options.delay.show)};Tooltip.prototype.isInStateTrue=function(){for(var key in this.inState){if(this.inState[key])return true}return false};Tooltip.prototype.leave=function(obj){var self=obj instanceof this.constructor?obj:$(obj.currentTarget).data("bs."+this.type);if(!self){self=new this.constructor(obj.currentTarget,this.getDelegateOptions());$(obj.currentTarget).data("bs."+this.type,self)}if(obj instanceof $.Event){self.inState[obj.type=="focusout"?"focus":"hover"]=false}if(self.isInStateTrue())return;clearTimeout(self.timeout);self.hoverState="out";if(!self.options.delay||!self.options.delay.hide)return self.hide();self.timeout=setTimeout(function(){if(self.hoverState=="out")self.hide()},self.options.delay.hide)};Tooltip.prototype.show=function(){var e=$.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(e);var inDom=$.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(e.isDefaultPrevented()||!inDom)return;var that=this;var $tip=this.tip();var tipId=this.getUID(this.type);this.setContent();$tip.attr("id",tipId);this.$element.attr("aria-describedby",tipId);if(this.options.animation)$tip.addClass("fade");var placement=typeof this.options.placement=="function"?this.options.placement.call(this,$tip[0],this.$element[0]):this.options.placement;var autoToken=\/\\s?auto?\\s?\/i;var autoPlace=autoToken.test(placement);if(autoPlace)placement=placement.replace(autoToken,"")||"top";$tip.detach().css({top:0,left:0,display:"block"}).addClass(placement).data("bs."+this.type,this);this.options.container?$tip.appendTo(this.options.container):$tip.insertAfter(this.$element);this.$element.trigger("inserted.bs."+this.type);var pos=this.getPosition();var actualWidth=$tip[0].offsetWidth;var actualHeight=$tip[0].offsetHeight;if(autoPlace){var orgPlacement=placement;var viewportDim=this.getPosition(this.$viewport);placement=placement=="bottom"&&pos.bottom+actualHeight>viewportDim.bottom?"top":placement=="top"&&pos.top-actualHeightviewportDim.width?"left":placement=="left"&&pos.left-actualWidthviewportDimensions.top+viewportDimensions.height){delta.top=viewportDimensions.top+viewportDimensions.height-bottomEdgeOffset}}else{var leftEdgeOffset=pos.left-viewportPadding;var rightEdgeOffset=pos.left+viewportPadding+actualWidth;if(leftEdgeOffsetviewportDimensions.right){delta.left=viewportDimensions.left+viewportDimensions.width-rightEdgeOffset}}return delta};Tooltip.prototype.getTitle=function(){var title;var $e=this.$element;var o=this.options;title=$e.attr("data-original-title")||(typeof o.title=="function"?o.title.call($e[0]):o.title);return title};Tooltip.prototype.getUID=function(prefix){do prefix+=~~(Math.random()*1e6);while(document.getElementById(prefix));return prefix};Tooltip.prototype.tip=function(){if(!this.$tip){this.$tip=$(this.options.template);if(this.$tip.length!=1){throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!")}}return this.$tip};Tooltip.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")};Tooltip.prototype.enable=function(){this.enabled=true};Tooltip.prototype.disable=function(){this.enabled=false};Tooltip.prototype.toggleEnabled=function(){this.enabled=!this.enabled};Tooltip.prototype.toggle=function(e){var self=this;if(e){self=$(e.currentTarget).data("bs."+this.type);if(!self){self=new this.constructor(e.currentTarget,this.getDelegateOptions());$(e.currentTarget).data("bs."+this.type,self)}}if(e){self.inState.click=!self.inState.click;if(self.isInStateTrue())self.enter(self);else self.leave(self)}else{self.tip().hasClass("in")?self.leave(self):self.enter(self)}};Tooltip.prototype.destroy=function(){var that=this;clearTimeout(this.timeout);this.hide(function(){that.$element.off("."+that.type).removeData("bs."+that.type);if(that.$tip){that.$tip.detach()}that.$tip=null;that.$arrow=null;that.$viewport=null})};function Plugin(option){return this.each(function(){var $this=$(this);var data=$this.data("bs.tooltip");var options=typeof option=="object"&&option;if(!data&&\/destroy|hide\/.test(option))return;if(!data)$this.data("bs.tooltip",data=new Tooltip(this,options));if(typeof option=="string")data[option]()})}var old=$.fn.tooltip;$.fn.tooltip=Plugin;$.fn.tooltip.Constructor=Tooltip;$.fn.tooltip.noConflict=function(){$.fn.tooltip=old;return this}}(jQuery);+function($){"use strict";var Popover=function(element,options){this.init("popover",element,options)};if(!$.fn.tooltip)throw new Error("Popover requires tooltip.js");Popover.VERSION="3.3.5";Popover.DEFAULTS=$.extend({},$.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'