aboutsummaryrefslogtreecommitdiffstats
path: root/library
diff options
context:
space:
mode:
authorzotlabs <mike@macgirvin.com>2017-07-05 15:35:05 -0700
committerzotlabs <mike@macgirvin.com>2017-07-05 15:35:05 -0700
commitfca8e0aa6ac9d4f2084371486e906d7e3726a5a5 (patch)
tree81d27ea002828a42c53541f741bad44684a2c601 /library
parent41111bcdadcd16ebc4f078fc812eb5a290f185e5 (diff)
parent8dd9ab05a97f92f9eca5d527e48272f3a44010a8 (diff)
downloadvolse-hubzilla-fca8e0aa6ac9d4f2084371486e906d7e3726a5a5.tar.gz
volse-hubzilla-fca8e0aa6ac9d4f2084371486e906d7e3726a5a5.tar.bz2
volse-hubzilla-fca8e0aa6ac9d4f2084371486e906d7e3726a5a5.zip
Merge branch 'dev' of https://github.com/redmatrix/hubzilla into dev_merge
Diffstat (limited to 'library')
-rw-r--r--library/blueimp_upload/.gitignore3
-rw-r--r--library/blueimp_upload/.jshintrc81
-rw-r--r--library/blueimp_upload/CONTRIBUTING.md43
-rw-r--r--library/blueimp_upload/Gruntfile.js37
-rw-r--r--library/blueimp_upload/LICENSE20
-rw-r--r--library/blueimp_upload/README.md58
-rw-r--r--library/blueimp_upload/angularjs.html14
-rw-r--r--library/blueimp_upload/basic-plus.html14
-rw-r--r--library/blueimp_upload/basic.html14
-rw-r--r--library/blueimp_upload/blueimp-file-upload.jquery.json50
-rwxr-xr-xlibrary/blueimp_upload/bower-version-update.js16
-rw-r--r--library/blueimp_upload/bower.json29
-rw-r--r--library/blueimp_upload/cors/postmessage.html6
-rw-r--r--library/blueimp_upload/cors/result.html4
-rw-r--r--library/blueimp_upload/css/demo-ie8.css4
-rw-r--r--library/blueimp_upload/css/demo.css4
-rw-r--r--library/blueimp_upload/css/jquery.fileupload-noscript.css6
-rw-r--r--library/blueimp_upload/css/jquery.fileupload-ui-noscript.css4
-rw-r--r--library/blueimp_upload/css/jquery.fileupload-ui.css4
-rw-r--r--library/blueimp_upload/css/jquery.fileupload.css7
-rw-r--r--library/blueimp_upload/css/style.css4
-rw-r--r--library/blueimp_upload/index.html12
-rw-r--r--library/blueimp_upload/jquery-ui.html14
-rw-r--r--library/blueimp_upload/js/app.js8
-rw-r--r--library/blueimp_upload/js/cors/jquery.postmessage-transport.js17
-rw-r--r--library/blueimp_upload/js/cors/jquery.xdr-transport.js11
-rw-r--r--library/blueimp_upload/js/jquery.fileupload-angular.js50
-rw-r--r--library/blueimp_upload/js/jquery.fileupload-audio.js15
-rw-r--r--library/blueimp_upload/js/jquery.fileupload-image.js23
-rw-r--r--[-rwxr-xr-x]library/blueimp_upload/js/jquery.fileupload-jquery-ui.js19
-rw-r--r--library/blueimp_upload/js/jquery.fileupload-process.js18
-rw-r--r--library/blueimp_upload/js/jquery.fileupload-ui.js23
-rw-r--r--library/blueimp_upload/js/jquery.fileupload-validate.js16
-rw-r--r--library/blueimp_upload/js/jquery.fileupload-video.js15
-rw-r--r--library/blueimp_upload/js/jquery.fileupload.js71
-rw-r--r--library/blueimp_upload/js/jquery.iframe-transport.js22
-rw-r--r--library/blueimp_upload/js/main.js6
-rw-r--r--library/blueimp_upload/js/vendor/jquery.ui.widget.js44
-rw-r--r--library/blueimp_upload/package.json39
-rw-r--r--library/blueimp_upload/server/gae-go/app/main.go297
-rw-r--r--library/blueimp_upload/server/gae-python/app.yaml5
-rw-r--r--library/blueimp_upload/server/gae-python/main.py208
-rw-r--r--library/blueimp_upload/server/node/.gitignore2
-rw-r--r--library/blueimp_upload/server/node/package.json41
-rw-r--r--library/blueimp_upload/server/node/public/files/.gitignore2
-rwxr-xr-xlibrary/blueimp_upload/server/node/server.js292
-rw-r--r--library/blueimp_upload/server/node/tmp/.gitignore0
-rw-r--r--library/blueimp_upload/server/php/Dockerfile38
-rwxr-xr-xlibrary/blueimp_upload/server/php/UploadHandler.php250
-rw-r--r--library/blueimp_upload/server/php/docker-compose.yml6
-rw-r--r--library/blueimp_upload/server/php/files/.htaccess14
-rw-r--r--library/blueimp_upload/server/php/index.php4
-rw-r--r--library/blueimp_upload/test/index.html16
-rw-r--r--library/blueimp_upload/test/test.js10
-rw-r--r--library/bootstrap/css/bootstrap-reboot.css.map2
-rw-r--r--library/bootstrap/css/bootstrap.css110
-rw-r--r--library/bootstrap/css/bootstrap.css.map2
-rw-r--r--library/bootstrap/css/bootstrap.min.css2
-rw-r--r--library/bootstrap/css/bootstrap.min.css.map2
-rw-r--r--library/bootstrap/js/bootstrap.js240
-rw-r--r--library/oauth2/.gitignore5
-rw-r--r--library/oauth2/.travis.yml30
-rw-r--r--library/oauth2/CHANGELOG.md152
-rw-r--r--library/oauth2/LICENSE21
-rw-r--r--library/oauth2/README.md8
-rw-r--r--library/oauth2/phpunit.xml25
-rw-r--r--library/oauth2/src/OAuth2/Autoloader.php48
-rw-r--r--library/oauth2/src/OAuth2/ClientAssertionType/ClientAssertionTypeInterface.php15
-rw-r--r--library/oauth2/src/OAuth2/ClientAssertionType/HttpBasic.php123
-rw-r--r--library/oauth2/src/OAuth2/Controller/AuthorizeController.php388
-rw-r--r--library/oauth2/src/OAuth2/Controller/AuthorizeControllerInterface.php43
-rw-r--r--library/oauth2/src/OAuth2/Controller/ResourceController.php111
-rw-r--r--library/oauth2/src/OAuth2/Controller/ResourceControllerInterface.php26
-rw-r--r--library/oauth2/src/OAuth2/Controller/TokenController.php278
-rw-r--r--library/oauth2/src/OAuth2/Controller/TokenControllerInterface.php32
-rw-r--r--library/oauth2/src/OAuth2/Encryption/EncryptionInterface.php11
-rw-r--r--library/oauth2/src/OAuth2/Encryption/FirebaseJwt.php47
-rw-r--r--library/oauth2/src/OAuth2/Encryption/Jwt.php173
-rw-r--r--library/oauth2/src/OAuth2/GrantType/AuthorizationCode.php100
-rw-r--r--library/oauth2/src/OAuth2/GrantType/ClientCredentials.php67
-rw-r--r--library/oauth2/src/OAuth2/GrantType/GrantTypeInterface.php20
-rw-r--r--library/oauth2/src/OAuth2/GrantType/JwtBearer.php226
-rw-r--r--library/oauth2/src/OAuth2/GrantType/RefreshToken.php111
-rw-r--r--library/oauth2/src/OAuth2/GrantType/UserCredentials.php83
-rw-r--r--library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeController.php106
-rw-r--r--library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php10
-rw-r--r--library/oauth2/src/OAuth2/OpenID/Controller/UserInfoController.php58
-rw-r--r--library/oauth2/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php23
-rw-r--r--library/oauth2/src/OAuth2/OpenID/GrantType/AuthorizationCode.php33
-rw-r--r--library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php60
-rw-r--r--library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php27
-rw-r--r--library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdToken.php24
-rw-r--r--library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php9
-rw-r--r--library/oauth2/src/OAuth2/OpenID/ResponseType/IdToken.php124
-rw-r--r--library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php29
-rw-r--r--library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenToken.php27
-rw-r--r--library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php9
-rw-r--r--library/oauth2/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php37
-rw-r--r--library/oauth2/src/OAuth2/OpenID/Storage/UserClaimsInterface.php38
-rw-r--r--library/oauth2/src/OAuth2/Request.php213
-rw-r--r--library/oauth2/src/OAuth2/RequestInterface.php16
-rw-r--r--library/oauth2/src/OAuth2/Response.php369
-rw-r--r--library/oauth2/src/OAuth2/ResponseInterface.php24
-rw-r--r--library/oauth2/src/OAuth2/ResponseType/AccessToken.php194
-rw-r--r--library/oauth2/src/OAuth2/ResponseType/AccessTokenInterface.php34
-rw-r--r--library/oauth2/src/OAuth2/ResponseType/AuthorizationCode.php100
-rw-r--r--library/oauth2/src/OAuth2/ResponseType/AuthorizationCodeInterface.php30
-rw-r--r--library/oauth2/src/OAuth2/ResponseType/JwtAccessToken.php124
-rw-r--r--library/oauth2/src/OAuth2/ResponseType/ResponseTypeInterface.php8
-rw-r--r--library/oauth2/src/OAuth2/Scope.php103
-rw-r--r--library/oauth2/src/OAuth2/ScopeInterface.php40
-rw-r--r--library/oauth2/src/OAuth2/Server.php832
-rw-r--r--library/oauth2/src/OAuth2/Storage/AccessTokenInterface.php64
-rw-r--r--library/oauth2/src/OAuth2/Storage/AuthorizationCodeInterface.php86
-rw-r--r--library/oauth2/src/OAuth2/Storage/Cassandra.php480
-rw-r--r--library/oauth2/src/OAuth2/Storage/ClientCredentialsInterface.php49
-rw-r--r--library/oauth2/src/OAuth2/Storage/ClientInterface.php66
-rwxr-xr-xlibrary/oauth2/src/OAuth2/Storage/CouchbaseDB.php331
-rw-r--r--library/oauth2/src/OAuth2/Storage/DynamoDB.php540
-rw-r--r--library/oauth2/src/OAuth2/Storage/JwtAccessToken.php88
-rw-r--r--library/oauth2/src/OAuth2/Storage/JwtAccessTokenInterface.php14
-rw-r--r--library/oauth2/src/OAuth2/Storage/JwtBearerInterface.php74
-rw-r--r--library/oauth2/src/OAuth2/Storage/Memory.php381
-rw-r--r--library/oauth2/src/OAuth2/Storage/Mongo.php339
-rw-r--r--library/oauth2/src/OAuth2/Storage/Pdo.php553
-rw-r--r--library/oauth2/src/OAuth2/Storage/PublicKeyInterface.php16
-rw-r--r--library/oauth2/src/OAuth2/Storage/Redis.php321
-rw-r--r--library/oauth2/src/OAuth2/Storage/RefreshTokenInterface.php82
-rw-r--r--library/oauth2/src/OAuth2/Storage/ScopeInterface.php46
-rw-r--r--library/oauth2/src/OAuth2/Storage/UserCredentialsInterface.php52
-rw-r--r--library/oauth2/src/OAuth2/TokenType/Bearer.php130
-rw-r--r--library/oauth2/src/OAuth2/TokenType/Mac.php22
-rw-r--r--library/oauth2/src/OAuth2/TokenType/TokenTypeInterface.php21
-rw-r--r--library/oauth2/test/OAuth2/AutoloadTest.php16
-rw-r--r--library/oauth2/test/OAuth2/Controller/AuthorizeControllerTest.php492
-rw-r--r--library/oauth2/test/OAuth2/Controller/ResourceControllerTest.php175
-rw-r--r--library/oauth2/test/OAuth2/Controller/TokenControllerTest.php289
-rw-r--r--library/oauth2/test/OAuth2/Encryption/FirebaseJwtTest.php102
-rw-r--r--library/oauth2/test/OAuth2/Encryption/JwtTest.php102
-rw-r--r--library/oauth2/test/OAuth2/GrantType/AuthorizationCodeTest.php207
-rw-r--r--library/oauth2/test/OAuth2/GrantType/ClientCredentialsTest.php159
-rw-r--r--library/oauth2/test/OAuth2/GrantType/ImplicitTest.php143
-rw-r--r--library/oauth2/test/OAuth2/GrantType/JwtBearerTest.php360
-rw-r--r--library/oauth2/test/OAuth2/GrantType/RefreshTokenTest.php204
-rw-r--r--library/oauth2/test/OAuth2/GrantType/UserCredentialsTest.php172
-rw-r--r--library/oauth2/test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php182
-rw-r--r--library/oauth2/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php44
-rw-r--r--library/oauth2/test/OAuth2/OpenID/GrantType/AuthorizationCodeTest.php57
-rw-r--r--library/oauth2/test/OAuth2/OpenID/ResponseType/CodeIdTokenTest.php182
-rw-r--r--library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTest.php184
-rw-r--r--library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTokenTest.php91
-rw-r--r--library/oauth2/test/OAuth2/OpenID/Storage/AuthorizationCodeTest.php95
-rw-r--r--library/oauth2/test/OAuth2/OpenID/Storage/UserClaimsTest.php41
-rw-r--r--library/oauth2/test/OAuth2/RequestTest.php98
-rw-r--r--library/oauth2/test/OAuth2/ResponseTest.php17
-rw-r--r--library/oauth2/test/OAuth2/ResponseType/AccessTokenTest.php107
-rw-r--r--library/oauth2/test/OAuth2/ResponseType/JwtAccessTokenTest.php160
-rw-r--r--library/oauth2/test/OAuth2/ScopeTest.php42
-rw-r--r--library/oauth2/test/OAuth2/ServerTest.php684
-rw-r--r--library/oauth2/test/OAuth2/Storage/AccessTokenTest.php102
-rw-r--r--library/oauth2/test/OAuth2/Storage/AuthorizationCodeTest.php106
-rw-r--r--library/oauth2/test/OAuth2/Storage/ClientCredentialsTest.php28
-rw-r--r--library/oauth2/test/OAuth2/Storage/ClientTest.php110
-rw-r--r--library/oauth2/test/OAuth2/Storage/DynamoDBTest.php40
-rw-r--r--library/oauth2/test/OAuth2/Storage/JwtAccessTokenTest.php41
-rw-r--r--library/oauth2/test/OAuth2/Storage/JwtBearerTest.php25
-rw-r--r--library/oauth2/test/OAuth2/Storage/PdoTest.php39
-rw-r--r--library/oauth2/test/OAuth2/Storage/PublicKeyTest.php29
-rw-r--r--library/oauth2/test/OAuth2/Storage/RefreshTokenTest.php41
-rw-r--r--library/oauth2/test/OAuth2/Storage/ScopeTest.php53
-rw-r--r--library/oauth2/test/OAuth2/Storage/UserCredentialsTest.php40
-rw-r--r--library/oauth2/test/OAuth2/TokenType/BearerTest.php58
-rw-r--r--library/oauth2/test/bootstrap.php12
-rw-r--r--library/oauth2/test/cleanup.php15
-rw-r--r--library/oauth2/test/config/keys/id_rsa15
-rw-r--r--library/oauth2/test/config/keys/id_rsa.pub16
-rw-r--r--library/oauth2/test/config/storage.json181
-rw-r--r--library/oauth2/test/lib/OAuth2/Request/TestRequest.php61
-rwxr-xr-xlibrary/oauth2/test/lib/OAuth2/Storage/BaseTest.php34
-rwxr-xr-xlibrary/oauth2/test/lib/OAuth2/Storage/Bootstrap.php888
-rw-r--r--library/oauth2/test/lib/OAuth2/Storage/NullStorage.php32
181 files changed, 1103 insertions, 16255 deletions
diff --git a/library/blueimp_upload/.gitignore b/library/blueimp_upload/.gitignore
deleted file mode 100644
index 29a41a8c4..000000000
--- a/library/blueimp_upload/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-.DS_Store
-*.pyc
-node_modules
diff --git a/library/blueimp_upload/.jshintrc b/library/blueimp_upload/.jshintrc
deleted file mode 100644
index 4ad82e664..000000000
--- a/library/blueimp_upload/.jshintrc
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.)
- "camelcase" : true, // true: Identifiers must be in camelCase
- "curly" : true, // true: Require {} for every new block or scope
- "eqeqeq" : true, // true: Require triple equals (===) for comparison
- "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty()
- "immed" : true, // true: Require immediate invocations to be wrapped in parens
- // e.g. `(function () { } ());`
- "indent" : 4, // {int} Number of spaces to use for indentation
- "latedef" : true, // true: Require variables/functions to be defined before being used
- "newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()`
- "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
- "noempty" : true, // true: Prohibit use of empty blocks
- "nonew" : true, // true: Prohibit use of constructors for side-effects (without assignment)
- "plusplus" : false, // true: Prohibit use of `++` & `--`
- "quotmark" : "single", // Quotation mark consistency:
- // false : do nothing (default)
- // true : ensure whatever is used is consistent
- // "single" : require single quotes
- // "double" : require double quotes
- "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
- "unused" : true, // true: Require all defined variables be used
- "strict" : true, // true: Requires all functions run in ES5 Strict Mode
- "trailing" : true, // true: Prohibit trailing whitespaces
- "maxparams" : false, // {int} Max number of formal params allowed per function
- "maxdepth" : false, // {int} Max depth of nested blocks (within functions)
- "maxstatements" : false, // {int} Max number statements per function
- "maxcomplexity" : false, // {int} Max cyclomatic complexity per function
- "maxlen" : false, // {int} Max number of characters per line
-
- // Relaxing
- "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
- "boss" : false, // true: Tolerate assignments where comparisons would be expected
- "debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
- "eqnull" : false, // true: Tolerate use of `== null`
- "es5" : false, // true: Allow ES5 syntax (ex: getters and setters)
- "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`)
- "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
- // (ex: `for each`, multiple try/catch, function expression…)
- "evil" : false, // true: Tolerate use of `eval` and `new Function()`
- "expr" : false, // true: Tolerate `ExpressionStatement` as Programs
- "funcscope" : false, // true: Tolerate defining variables inside control statements"
- "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict')
- "iterator" : false, // true: Tolerate using the `__iterator__` property
- "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
- "laxbreak" : false, // true: Tolerate possibly unsafe line breakings
- "laxcomma" : false, // true: Tolerate comma-first style coding
- "loopfunc" : false, // true: Tolerate functions being defined in loops
- "multistr" : false, // true: Tolerate multi-line strings
- "proto" : false, // true: Tolerate using the `__proto__` property
- "scripturl" : false, // true: Tolerate script-targeted URLs
- "smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment
- "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
- "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
- "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
- "validthis" : false, // true: Tolerate using this in a non-constructor function
-
- // Environments
- "browser" : false, // Web Browser (window, document, etc)
- "couch" : false, // CouchDB
- "devel" : false, // Development/debugging (alert, confirm, etc)
- "dojo" : false, // Dojo Toolkit
- "jquery" : false, // jQuery
- "mootools" : false, // MooTools
- "node" : false, // Node.js
- "nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
- "prototypejs" : false, // Prototype and Scriptaculous
- "rhino" : false, // Rhino
- "worker" : false, // Web Workers
- "wsh" : false, // Windows Scripting Host
- "yui" : false, // Yahoo User Interface
-
- // Legacy
- "nomen" : true, // true: Prohibit dangling `_` in variables
- "onevar" : true, // true: Allow only one `var` statement per function
- "passfail" : false, // true: Stop on first error
- "white" : true, // true: Check against strict whitespace and indentation rules
-
- // Custom Globals
- "globals" : {} // additional predefined global variables
-}
diff --git a/library/blueimp_upload/CONTRIBUTING.md b/library/blueimp_upload/CONTRIBUTING.md
index b8708f8b6..e182f9b37 100644
--- a/library/blueimp_upload/CONTRIBUTING.md
+++ b/library/blueimp_upload/CONTRIBUTING.md
@@ -1,42 +1,15 @@
-# Issue Guidelines
+Please follow these pull request guidelines:
-The issues tracker should only be used for **bugs** or **feature requests**.
-
-Please post **support requests** and **general discussions** about this project to the [support forum](https://groups.google.com/d/forum/jquery-fileupload).
-
-## Bugs
-
-Please follow these guidelines before reporting a bug:
-
-1. **Update to the latest version** &mdash; Check if you can reproduce the issue with the latest version from the `master` branch.
-
-2. **Use the GitHub issue search** &mdash; check if the issue has already been reported. If it has been, please comment on the existing issue.
-
-3. **Isolate the demonstrable problem** &mdash; Try to reproduce the problem with the [Demo](https://blueimp.github.io/jQuery-File-Upload/) or with a reduced test case that includes the least amount of code necessary to reproduce the problem.
-
-4. **Provide a means to reproduce the problem** &mdash; Please provide as much details as possible, e.g. server information, browser and operating system versions, steps to reproduce the problem. If possible, provide a link to your reduced test case, e.g. via [JSFiddle](http://jsfiddle.net/).
-
-
-## Feature requests
-
-Please follow the bug guidelines above for feature requests, i.e. update to the latest version and search for exising issues before posting a new request.
-
-Generally, feature requests might be accepted if the implementation would benefit a broader use case or the project could be considered incomplete without that feature.
-
-If you need help integrating this project into another framework, please post your request to the [support forum](https://groups.google.com/d/forum/jquery-fileupload).
-
-## Pull requests
-
-[Pull requests](https://help.github.com/articles/using-pull-requests) are welcome and the preferred way of accepting code contributions.
+1. Update your fork to the latest upstream version.
-However, if you add a server-side upload handler implementation for another framework, please continue to maintain this version in your own fork without sending a pull request. You are welcome to add a link and possibly documentation about your implementation to the [Wiki](https://github.com/blueimp/jQuery-File-Upload/wiki).
+2. Follow the coding conventions of the original source files (indentation, spaces, brackets layout).
-Please follow these guidelines before sending a pull request:
+3. Code changes must pass JSHint validation with the `.jshintrc` settings of this project.
-1. Update your fork to the latest upstream version.
+4. Code changes must pass the QUnit tests defined in the `test` folder.
-2. Follow the coding conventions of the original repository. Changes to one of the JavaScript source files are required to pass the [JSHint](http://www.jshint.com/) validation tool.
+5. New features should be covered by accompanying QUnit tests.
-3. Keep your commits as atomar as possible, i.e. create a new commit for every single bug fix or feature added.
+6. Keep your commits as atomic as possible, i.e. create a new commit for every single bug fix or feature added.
-4. Always add meaningfull commit messages.
+7. Always add meaningful commit messages.
diff --git a/library/blueimp_upload/Gruntfile.js b/library/blueimp_upload/Gruntfile.js
deleted file mode 100644
index dcdb5d57a..000000000
--- a/library/blueimp_upload/Gruntfile.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * jQuery File Upload Gruntfile
- * https://github.com/blueimp/jQuery-File-Upload
- *
- * Copyright 2013, Sebastian Tschan
- * https://blueimp.net
- *
- * Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
- */
-
-/*global module */
-
-module.exports = function (grunt) {
- 'use strict';
-
- grunt.initConfig({
- jshint: {
- options: {
- jshintrc: '.jshintrc'
- },
- all: [
- 'Gruntfile.js',
- 'js/cors/*.js',
- 'js/*.js',
- 'server/node/server.js',
- 'test/test.js'
- ]
- }
- });
-
- grunt.loadNpmTasks('grunt-contrib-jshint');
- grunt.loadNpmTasks('grunt-bump-build-git');
- grunt.registerTask('test', ['jshint']);
- grunt.registerTask('default', ['test']);
-
-};
diff --git a/library/blueimp_upload/LICENSE b/library/blueimp_upload/LICENSE
new file mode 100644
index 000000000..0ecca3e8c
--- /dev/null
+++ b/library/blueimp_upload/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 jQuery-File-Upload Authors
+
+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.
diff --git a/library/blueimp_upload/README.md b/library/blueimp_upload/README.md
index 3aa33de42..56785b847 100644
--- a/library/blueimp_upload/README.md
+++ b/library/blueimp_upload/README.md
@@ -11,17 +11,6 @@ Supports cross-domain, chunked and resumable file uploads and client-side image
* [How to setup the plugin on your website](https://github.com/blueimp/jQuery-File-Upload/wiki/Setup)
* [How to use only the basic plugin (minimal setup guide).](https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin)
-## Support
-
-* **[Support Forum](https://groups.google.com/d/forum/jquery-fileupload)**
-**Support requests** and **general discussions** about the File Upload plugin can be posted to the official
-[Support Forum](https://groups.google.com/d/forum/jquery-fileupload).
-If your question is not directly related to the File Upload plugin, you might have a better chance to get a reply by posting to [Stack Overflow](http://stackoverflow.com/questions/tagged/blueimp+jquery+file-upload).
-
-* Bugs and Feature requests
-**Bugs** and **Feature requests** can be reported using the [issues tracker](https://github.com/blueimp/jQuery-File-Upload/issues).
-Please read the [issue guidelines](https://github.com/blueimp/jQuery-File-Upload/blob/master/CONTRIBUTING.md) before posting.
-
## Features
* **Multiple file upload:**
Allows to select multiple files at once and upload them simultaneously.
@@ -60,28 +49,18 @@ Please read the [issue guidelines](https://github.com/blueimp/jQuery-File-Upload
### Mandatory requirements
* [jQuery](https://jquery.com/) v. 1.6+
-* [jQuery UI widget factory](https://api.jqueryui.com/jQuery.widget/) v. 1.9+ (included)
-* [jQuery Iframe Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/jquery.iframe-transport.js) (included)
-
-The jQuery UI widget factory is a requirement for the basic File Upload plugin, but very lightweight without any other dependencies from the jQuery UI suite.
-
-The jQuery Iframe Transport is required for [browsers without XHR file upload support](https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support).
+* [jQuery UI widget factory](https://api.jqueryui.com/jQuery.widget/) v. 1.9+ (included): Required for the basic File Upload plugin, but very lightweight without any other dependencies from the jQuery UI suite.
+* [jQuery Iframe Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/jquery.iframe-transport.js) (included): Required for [browsers without XHR file upload support](https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support).
### Optional requirements
-* [JavaScript Templates engine](https://github.com/blueimp/JavaScript-Templates) v. 2.5.4+
-* [JavaScript Load Image library](https://github.com/blueimp/JavaScript-Load-Image) v. 1.13.0+
-* [JavaScript Canvas to Blob polyfill](https://github.com/blueimp/JavaScript-Canvas-to-Blob) v. 2.1.1+
-* [blueimp Gallery](https://github.com/blueimp/Gallery) v. 2.15.1+
-* [Bootstrap CSS framework](http://getbootstrap.com/) v. 3.2.0+
+* [JavaScript Templates engine](https://github.com/blueimp/JavaScript-Templates) v. 2.5.4+: Used to render the selected and uploaded files for the Basic Plus UI and jQuery UI versions.
+* [JavaScript Load Image library](https://github.com/blueimp/JavaScript-Load-Image) v. 1.13.0+: Required for the image previews and resizing functionality.
+* [JavaScript Canvas to Blob polyfill](https://github.com/blueimp/JavaScript-Canvas-to-Blob) v. 2.1.1+:Required for the image previews and resizing functionality.
+* [blueimp Gallery](https://github.com/blueimp/Gallery) v. 2.15.1+: Used to display the uploaded images in a lightbox.
+* [Bootstrap](http://getbootstrap.com/) v. 3.2.0+
* [Glyphicons](http://glyphicons.com/)
-The JavaScript Templates engine is used to render the selected and uploaded files for the Basic Plus UI and jQuery UI versions.
-
-The JavaScript Load Image library and JavaScript Canvas to Blob polyfill are required for the image previews and resizing functionality.
-
-The blueimp Gallery is used to display the uploaded images in a lightbox.
-
-The user interface of all versions except the jQuery UI version is built with Twitter's [Bootstrap](http://getbootstrap.com/) framework and icons from [Glyphicons](http://glyphicons.com/).
+The user interface of all versions except the jQuery UI version is built with [Bootstrap](http://getbootstrap.com/) and icons from [Glyphicons](http://glyphicons.com/).
### Cross-domain requirements
[Cross-domain File Uploads](https://github.com/blueimp/jQuery-File-Upload/wiki/Cross-domain-uploads) using the [Iframe Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/jquery.iframe-transport.js) require a redirect back to the origin server to retrieve the upload results. The [example implementation](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/main.js) makes use of [result.html](https://github.com/blueimp/jQuery-File-Upload/blob/master/cors/result.html) as a static redirect page for the origin server.
@@ -89,6 +68,10 @@ The user interface of all versions except the jQuery UI version is built with Tw
The repository also includes the [jQuery XDomainRequest Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/cors/jquery.xdr-transport.js), which enables limited cross-domain AJAX requests in Microsoft Internet Explorer 8 and 9 (IE 10 supports cross-domain XHR requests).
The XDomainRequest object allows GET and POST requests only and doesn't support file uploads. It is used on the [Demo](https://blueimp.github.io/jQuery-File-Upload/) to delete uploaded files from the cross-domain demo file upload service.
+### Custom Backends
+
+You can add support for various backends by adhering to the specification [outlined here](https://github.com/blueimp/jQuery-File-Upload/wiki/JSON-Response).
+
## Browsers
### Desktop browsers
@@ -110,14 +93,15 @@ The File Upload plugin has been tested with and supports the following mobile br
* Opera Mobile 12.0+
### Supported features
-For a detailed overview of the features supported by each browser version please have a look at the [Extended browser support information](https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support).
+For a detailed overview of the features supported by each browser version, please have a look at the [Extended browser support information](https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support).
-## License
-Released under the [MIT license](http://www.opensource.org/licenses/MIT).
+## Contributing
+**Bug fixes** and **new features** can be proposed using [pull requests](https://github.com/blueimp/jQuery-File-Upload/pulls).
+Please read the [contribution guidelines](https://github.com/blueimp/jQuery-File-Upload/blob/master/CONTRIBUTING.md) before submitting a pull request.
-## Donations
-jQuery File Upload is free software, but you can donate to support the developer, Sebastian Tschan:
-
-Flattr: [![Flattr](https://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/thing/286433/jQuery-File-Upload-Plugin)
+## Support
+This project is actively maintained, but there is no official support channel.
+If you have a question that another developer might help you with, please post to [Stack Overflow](http://stackoverflow.com/questions/tagged/blueimp+jquery+file-upload) and tag your question with `blueimp jquery file upload`.
-PayPal: [![PayPal](https://www.paypalobjects.com/WEBSCR-640-20110429-1/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=PYWYSYP77KL54)
+## License
+Released under the [MIT license](https://opensource.org/licenses/MIT).
diff --git a/library/blueimp_upload/angularjs.html b/library/blueimp_upload/angularjs.html
index 2a3ca2007..4858c8600 100644
--- a/library/blueimp_upload/angularjs.html
+++ b/library/blueimp_upload/angularjs.html
@@ -1,14 +1,14 @@
<!DOCTYPE HTML>
<!--
/*
- * jQuery File Upload Plugin AngularJS Demo 2.2.0
+ * jQuery File Upload Plugin AngularJS Demo
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2013, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
-->
<html lang="en">
@@ -157,9 +157,9 @@
</div>
<div class="panel-body">
<ul>
- <li>The maximum file size for uploads in this demo is <strong>5 MB</strong> (default file size is unlimited).</li>
+ <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li>
<li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li>
- <li>Uploaded files will be deleted automatically after <strong>5 minutes</strong> (demo setting).</li>
+ <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li>
<li>You can <strong>drag &amp; drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li>
<li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li>
<li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li>
@@ -177,8 +177,8 @@
<a class="play-pause"></a>
<ol class="indicator"></ol>
</div>
-<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
-<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
+<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
<script src="js/vendor/jquery.ui.widget.js"></script>
<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
@@ -207,5 +207,5 @@
<script src="js/jquery.fileupload-angular.js"></script>
<!-- The main application script -->
<script src="js/app.js"></script>
-</body>
+</body>
</html>
diff --git a/library/blueimp_upload/basic-plus.html b/library/blueimp_upload/basic-plus.html
index 59b73b60c..9e5c2321f 100644
--- a/library/blueimp_upload/basic-plus.html
+++ b/library/blueimp_upload/basic-plus.html
@@ -1,14 +1,14 @@
<!DOCTYPE HTML>
<!--
/*
- * jQuery File Upload Plugin Basic Plus Demo 1.4.0
+ * jQuery File Upload Plugin Basic Plus Demo
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2013, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
-->
<html lang="en">
@@ -86,9 +86,9 @@
</div>
<div class="panel-body">
<ul>
- <li>The maximum file size for uploads in this demo is <strong>5 MB</strong> (default file size is unlimited).</li>
+ <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li>
<li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li>
- <li>Uploaded files will be deleted automatically after <strong>5 minutes</strong> (demo setting).</li>
+ <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li>
<li>You can <strong>drag &amp; drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li>
<li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li>
<li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li>
@@ -96,7 +96,7 @@
</div>
</div>
</div>
-<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
<script src="js/vendor/jquery.ui.widget.js"></script>
<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
@@ -150,7 +150,7 @@ $(function () {
dataType: 'json',
autoUpload: false,
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
- maxFileSize: 5000000, // 5 MB
+ maxFileSize: 999000,
// Enable image resizing, except for Android and Opera,
// which actually support image resizing, but fail to
// send Blob objects via XHR requests:
@@ -222,5 +222,5 @@ $(function () {
.parent().addClass($.support.fileInput ? undefined : 'disabled');
});
</script>
-</body>
+</body>
</html>
diff --git a/library/blueimp_upload/basic.html b/library/blueimp_upload/basic.html
index f248f4d80..c0df639b4 100644
--- a/library/blueimp_upload/basic.html
+++ b/library/blueimp_upload/basic.html
@@ -1,14 +1,14 @@
<!DOCTYPE HTML>
<!--
/*
- * jQuery File Upload Plugin Basic Demo 1.3.0
+ * jQuery File Upload Plugin Basic Demo
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2013, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
-->
<html lang="en">
@@ -86,17 +86,17 @@
</div>
<div class="panel-body">
<ul>
- <li>The maximum file size for uploads in this demo is <strong>5 MB</strong> (default file size is unlimited).</li>
+ <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li>
<li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li>
- <li>Uploaded files will be deleted automatically after <strong>5 minutes</strong> (demo setting).</li>
+ <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li>
<li>You can <strong>drag &amp; drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li>
<li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li>
- <li>Built with Twitter's <a href="http://twitter.github.com/bootstrap/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li>
+ <li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li>
</ul>
</div>
</div>
</div>
-<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
<script src="js/vendor/jquery.ui.widget.js"></script>
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
@@ -132,5 +132,5 @@ $(function () {
.parent().addClass($.support.fileInput ? undefined : 'disabled');
});
</script>
-</body>
+</body>
</html>
diff --git a/library/blueimp_upload/blueimp-file-upload.jquery.json b/library/blueimp_upload/blueimp-file-upload.jquery.json
deleted file mode 100644
index d6d8c911c..000000000
--- a/library/blueimp_upload/blueimp-file-upload.jquery.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
- "name": "blueimp-file-upload",
- "version": "9.8.0",
- "title": "jQuery File Upload",
- "author": {
- "name": "Sebastian Tschan",
- "url": "https://blueimp.net"
- },
- "licenses": [
- {
- "type": "MIT",
- "url": "http://www.opensource.org/licenses/MIT"
- }
- ],
- "dependencies": {
- "jquery": ">=1.6"
- },
- "description": "File Upload widget with multiple file selection, drag&amp;drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.",
- "keywords": [
- "jquery",
- "file",
- "upload",
- "widget",
- "multiple",
- "selection",
- "drag",
- "drop",
- "progress",
- "preview",
- "cross-domain",
- "cross-site",
- "chunk",
- "resume",
- "gae",
- "go",
- "python",
- "php",
- "bootstrap"
- ],
- "homepage": "https://github.com/blueimp/jQuery-File-Upload",
- "docs": "https://github.com/blueimp/jQuery-File-Upload/wiki",
- "demo": "https://blueimp.github.io/jQuery-File-Upload/",
- "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues",
- "maintainers": [
- {
- "name": "Sebastian Tschan",
- "url": "https://blueimp.net"
- }
- ]
-}
diff --git a/library/blueimp_upload/bower-version-update.js b/library/blueimp_upload/bower-version-update.js
new file mode 100755
index 000000000..09ce3927e
--- /dev/null
+++ b/library/blueimp_upload/bower-version-update.js
@@ -0,0 +1,16 @@
+#!/usr/bin/env node
+
+'use strict';
+
+var path = require('path');
+var packageJSON = require(path.join(__dirname, 'package.json'));
+var bowerFile = path.join(__dirname, 'bower.json');
+var bowerJSON = require('bower-json').parse(
+ require(bowerFile),
+ {normalize: true}
+);
+bowerJSON.version = packageJSON.version;
+require('fs').writeFileSync(
+ bowerFile,
+ JSON.stringify(bowerJSON, null, 2) + '\n'
+);
diff --git a/library/blueimp_upload/bower.json b/library/blueimp_upload/bower.json
index c0d3d3259..90c74c792 100644
--- a/library/blueimp_upload/bower.json
+++ b/library/blueimp_upload/bower.json
@@ -1,8 +1,8 @@
{
"name": "blueimp-file-upload",
- "version": "9.8.0",
+ "version": "9.18.0",
"title": "jQuery File Upload",
- "description": "File Upload widget with multiple file selection, drag&amp;drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.",
+ "description": "File Upload widget with multiple file selection, drag&amp;drop support, progress bar, validation and preview images.",
"keywords": [
"jquery",
"file",
@@ -40,12 +40,7 @@
"url": "git://github.com/blueimp/jQuery-File-Upload.git"
},
"bugs": "https://github.com/blueimp/jQuery-File-Upload/issues",
- "licenses": [
- {
- "type": "MIT",
- "url": "http://www.opensource.org/licenses/MIT"
- }
- ],
+ "license": "MIT",
"dependencies": {
"jquery": ">=1.6",
"blueimp-tmpl": ">=2.5.4",
@@ -53,23 +48,7 @@
"blueimp-canvas-to-blob": ">=2.1.1"
},
"main": [
- "css/jquery.fileupload.css",
- "css/jquery.fileupload-ui.css",
- "css/jquery.fileupload-noscript.css",
- "css/jquery.fileupload-ui-noscript.css",
- "js/cors/jquery.postmessage-transport.js",
- "js/cors/jquery.xdr-transport.js",
- "js/vendor/jquery.ui.widget.js",
- "js/jquery.fileupload.js",
- "js/jquery.fileupload-process.js",
- "js/jquery.fileupload-validate.js",
- "js/jquery.fileupload-image.js",
- "js/jquery.fileupload-audio.js",
- "js/jquery.fileupload-video.js",
- "js/jquery.fileupload-ui.js",
- "js/jquery.fileupload-jquery-ui.js",
- "js/jquery.fileupload-angular.js",
- "js/jquery.iframe-transport.js"
+ "js/jquery.fileupload.js"
],
"ignore": [
"/*.*",
diff --git a/library/blueimp_upload/cors/postmessage.html b/library/blueimp_upload/cors/postmessage.html
index 3d1448f08..6db288cf9 100644
--- a/library/blueimp_upload/cors/postmessage.html
+++ b/library/blueimp_upload/cors/postmessage.html
@@ -1,14 +1,14 @@
<!DOCTYPE HTML>
<!--
/*
- * jQuery File Upload Plugin postMessage API 1.2.1
+ * jQuery File Upload Plugin postMessage API
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2011, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
-->
<html lang="en">
@@ -72,4 +72,4 @@ $(window).on('message', function (e) {
});
</script>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/library/blueimp_upload/cors/result.html b/library/blueimp_upload/cors/result.html
index 225131495..e3d629814 100644
--- a/library/blueimp_upload/cors/result.html
+++ b/library/blueimp_upload/cors/result.html
@@ -1,14 +1,14 @@
<!DOCTYPE HTML>
<!--
/*
- * jQuery Iframe Transport Plugin Redirect Page 2.0.1
+ * jQuery Iframe Transport Plugin Redirect Page
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
-->
<html lang="en">
diff --git a/library/blueimp_upload/css/demo-ie8.css b/library/blueimp_upload/css/demo-ie8.css
index 262493d08..e0e8ea9b0 100644
--- a/library/blueimp_upload/css/demo-ie8.css
+++ b/library/blueimp_upload/css/demo-ie8.css
@@ -1,13 +1,13 @@
@charset "UTF-8";
/*
- * jQuery File Upload Demo CSS Fixes for IE<9 1.0.0
+ * jQuery File Upload Demo CSS Fixes for IE<9
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2013, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
.navigation {
diff --git a/library/blueimp_upload/css/demo.css b/library/blueimp_upload/css/demo.css
index 2b4d43934..d7d524df5 100644
--- a/library/blueimp_upload/css/demo.css
+++ b/library/blueimp_upload/css/demo.css
@@ -1,13 +1,13 @@
@charset "UTF-8";
/*
- * jQuery File Upload Demo CSS 1.1.0
+ * jQuery File Upload Demo CSS
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2013, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
body {
diff --git a/library/blueimp_upload/css/jquery.fileupload-noscript.css b/library/blueimp_upload/css/jquery.fileupload-noscript.css
index 64d728fc3..2409bfb0a 100644
--- a/library/blueimp_upload/css/jquery.fileupload-noscript.css
+++ b/library/blueimp_upload/css/jquery.fileupload-noscript.css
@@ -1,20 +1,20 @@
@charset "UTF-8";
/*
- * jQuery File Upload Plugin NoScript CSS 1.2.0
+ * jQuery File Upload Plugin NoScript CSS
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2013, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
.fileinput-button input {
position: static;
opacity: 1;
filter: none;
- font-size: inherit;
+ font-size: inherit !important;
direction: inherit;
}
.fileinput-button span {
diff --git a/library/blueimp_upload/css/jquery.fileupload-ui-noscript.css b/library/blueimp_upload/css/jquery.fileupload-ui-noscript.css
index 87f110cdb..30651acf0 100644
--- a/library/blueimp_upload/css/jquery.fileupload-ui-noscript.css
+++ b/library/blueimp_upload/css/jquery.fileupload-ui-noscript.css
@@ -1,13 +1,13 @@
@charset "UTF-8";
/*
- * jQuery File Upload UI Plugin NoScript CSS 8.8.5
+ * jQuery File Upload UI Plugin NoScript CSS
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2012, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
.fileinput-button i,
diff --git a/library/blueimp_upload/css/jquery.fileupload-ui.css b/library/blueimp_upload/css/jquery.fileupload-ui.css
index 76fb376de..9e36c42c5 100644
--- a/library/blueimp_upload/css/jquery.fileupload-ui.css
+++ b/library/blueimp_upload/css/jquery.fileupload-ui.css
@@ -1,13 +1,13 @@
@charset "UTF-8";
/*
- * jQuery File Upload UI Plugin CSS 9.0.0
+ * jQuery File Upload UI Plugin CSS
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
.fileupload-buttonbar .btn,
diff --git a/library/blueimp_upload/css/jquery.fileupload.css b/library/blueimp_upload/css/jquery.fileupload.css
index fb6044d34..8ae3b09d4 100644
--- a/library/blueimp_upload/css/jquery.fileupload.css
+++ b/library/blueimp_upload/css/jquery.fileupload.css
@@ -1,18 +1,19 @@
@charset "UTF-8";
/*
- * jQuery File Upload Plugin CSS 1.3.0
+ * jQuery File Upload Plugin CSS
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2013, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
.fileinput-button {
position: relative;
overflow: hidden;
+ display: inline-block;
}
.fileinput-button input {
position: absolute;
@@ -21,7 +22,7 @@
margin: 0;
opacity: 0;
-ms-filter: 'alpha(opacity=0)';
- font-size: 200px;
+ font-size: 200px !important;
direction: ltr;
cursor: pointer;
}
diff --git a/library/blueimp_upload/css/style.css b/library/blueimp_upload/css/style.css
index b2c60a6f1..3aee25689 100644
--- a/library/blueimp_upload/css/style.css
+++ b/library/blueimp_upload/css/style.css
@@ -1,13 +1,13 @@
@charset "UTF-8";
/*
- * jQuery File Upload Plugin CSS Example 8.8.2
+ * jQuery File Upload Plugin CSS Example
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2013, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
body {
diff --git a/library/blueimp_upload/index.html b/library/blueimp_upload/index.html
index f92f04aab..2a8dc1521 100644
--- a/library/blueimp_upload/index.html
+++ b/library/blueimp_upload/index.html
@@ -1,14 +1,14 @@
<!DOCTYPE HTML>
<!--
/*
- * jQuery File Upload Plugin Demo 9.1.0
+ * jQuery File Upload Plugin Demo
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
-->
<html lang="en">
@@ -121,9 +121,9 @@
</div>
<div class="panel-body">
<ul>
- <li>The maximum file size for uploads in this demo is <strong>5 MB</strong> (default file size is unlimited).</li>
+ <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li>
<li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li>
- <li>Uploaded files will be deleted automatically after <strong>5 minutes</strong> (demo setting).</li>
+ <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li>
<li>You can <strong>drag &amp; drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li>
<li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li>
<li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li>
@@ -216,7 +216,7 @@
</tr>
{% } %}
</script>
-<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
<script src="js/vendor/jquery.ui.widget.js"></script>
<!-- The Templates plugin is included to render the upload/download listings -->
@@ -251,5 +251,5 @@
<!--[if (gte IE 8)&(lt IE 10)]>
<script src="js/cors/jquery.xdr-transport.js"></script>
<![endif]-->
-</body>
+</body>
</html>
diff --git a/library/blueimp_upload/jquery-ui.html b/library/blueimp_upload/jquery-ui.html
index d61ee5233..83fe9acd1 100644
--- a/library/blueimp_upload/jquery-ui.html
+++ b/library/blueimp_upload/jquery-ui.html
@@ -1,14 +1,14 @@
<!DOCTYPE HTML>
<!--
/*
- * jQuery File Upload Plugin jQuery UI Demo 9.1.0
+ * jQuery File Upload Plugin jQuery UI Demo
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2013, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
-->
<html lang="en">
@@ -127,9 +127,9 @@
<br>
<h3>Demo Notes</h3>
<ul>
- <li>The maximum file size for uploads in this demo is <strong>5 MB</strong> (default file size is unlimited).</li>
+ <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li>
<li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li>
- <li>Uploaded files will be deleted automatically after <strong>5 minutes</strong> (demo setting).</li>
+ <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li>
<li>You can <strong>drag &amp; drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li>
<li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li>
<li>Built with <a href="https://jqueryui.com">jQuery UI</a>.</li>
@@ -199,8 +199,8 @@
</tr>
{% } %}
</script>
-<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
-<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js"></script>
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
+<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<!-- The Templates plugin is included to render the upload/download listings -->
<script src="//blueimp.github.io/JavaScript-Templates/js/tmpl.min.js"></script>
<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
@@ -246,5 +246,5 @@ $('#theme-switcher').change(function () {
<!--[if (gte IE 8)&(lt IE 10)]>
<script src="js/cors/jquery.xdr-transport.js"></script>
<![endif]-->
-</body>
+</body>
</html>
diff --git a/library/blueimp_upload/js/app.js b/library/blueimp_upload/js/app.js
index 47b4f923b..e6b7bce3e 100644
--- a/library/blueimp_upload/js/app.js
+++ b/library/blueimp_upload/js/app.js
@@ -1,18 +1,18 @@
/*
- * jQuery File Upload Plugin Angular JS Example 1.2.1
+ * jQuery File Upload Plugin Angular JS Example
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2013, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
/* jshint nomen:false */
/* global window, angular */
-(function () {
+;(function () {
'use strict';
var isOnGitHub = window.location.hostname === 'blueimp.github.io',
@@ -37,7 +37,7 @@
// send Blob objects via XHR requests:
disableImageResize: /Android(?!.*Chrome)|Opera/
.test(window.navigator.userAgent),
- maxFileSize: 5000000,
+ maxFileSize: 999000,
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i
});
}
diff --git a/library/blueimp_upload/js/cors/jquery.postmessage-transport.js b/library/blueimp_upload/js/cors/jquery.postmessage-transport.js
index 2b4851e67..2a0c38cb6 100644
--- a/library/blueimp_upload/js/cors/jquery.postmessage-transport.js
+++ b/library/blueimp_upload/js/cors/jquery.postmessage-transport.js
@@ -1,21 +1,24 @@
/*
- * jQuery postMessage Transport Plugin 1.1.1
+ * jQuery postMessage Transport Plugin
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2011, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
-/* global define, window, document */
+/* global define, require, window, document */
-(function (factory) {
+;(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
define(['jquery'], factory);
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS:
+ factory(require('jquery'));
} else {
// Browser globals:
factory(window.jQuery);
@@ -61,6 +64,12 @@
loc = $('<a>').prop('href', options.postMessage)[0],
target = loc.protocol + '//' + loc.host,
xhrUpload = options.xhr().upload;
+ // IE always includes the port for the host property of a link
+ // element, but not in the location.host or origin property for the
+ // default http port 80 and https port 443, so we strip it:
+ if (/^(http:\/\/.+:80)|(https:\/\/.+:443)$/.test(target)) {
+ target = target.replace(/:(80|443)$/, '');
+ }
return {
send: function (_, completeCallback) {
counter += 1;
diff --git a/library/blueimp_upload/js/cors/jquery.xdr-transport.js b/library/blueimp_upload/js/cors/jquery.xdr-transport.js
index 0044cc2d5..a4e2699c6 100644
--- a/library/blueimp_upload/js/cors/jquery.xdr-transport.js
+++ b/library/blueimp_upload/js/cors/jquery.xdr-transport.js
@@ -1,24 +1,27 @@
/*
- * jQuery XDomainRequest Transport Plugin 1.1.3
+ * jQuery XDomainRequest Transport Plugin
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2011, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*
* Based on Julian Aubourg's ajaxHooks xdr.js:
* https://github.com/jaubourg/ajaxHooks/
*/
-/* global define, window, XDomainRequest */
+/* global define, require, window, XDomainRequest */
-(function (factory) {
+;(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
define(['jquery'], factory);
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS:
+ factory(require('jquery'));
} else {
// Browser globals:
factory(window.jQuery);
diff --git a/library/blueimp_upload/js/jquery.fileupload-angular.js b/library/blueimp_upload/js/jquery.fileupload-angular.js
index e4ef3926b..1c2055276 100644
--- a/library/blueimp_upload/js/jquery.fileupload-angular.js
+++ b/library/blueimp_upload/js/jquery.fileupload-angular.js
@@ -1,18 +1,18 @@
/*
- * jQuery File Upload AngularJS Plugin 2.2.0
+ * jQuery File Upload AngularJS Plugin
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2013, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
/* jshint nomen:false */
-/* global define, angular */
+/* global define, angular, require */
-(function (factory) {
+;(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
@@ -24,6 +24,16 @@
'./jquery.fileupload-video',
'./jquery.fileupload-validate'
], factory);
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS:
+ factory(
+ require('jquery'),
+ require('angular'),
+ require('./jquery.fileupload-image'),
+ require('./jquery.fileupload-audio'),
+ require('./jquery.fileupload-video'),
+ require('./jquery.fileupload-validate')
+ );
} else {
factory();
}
@@ -91,7 +101,7 @@
angular.forEach(data.files, function (file) {
filesCopy.push(file);
});
- scope.$apply(function () {
+ scope.$parent.$applyAsync(function () {
addFileMethods(scope, data);
var method = scope.option('prependFiles') ?
'unshift' : 'push';
@@ -100,7 +110,7 @@
data.process(function () {
return scope.process(data);
}).always(function () {
- scope.$apply(function () {
+ scope.$parent.$applyAsync(function () {
addFileMethods(scope, data);
scope.replace(filesCopy, data.files);
});
@@ -112,12 +122,6 @@
}
});
},
- progress: function (e, data) {
- if (e.isDefaultPrevented()) {
- return false;
- }
- data.scope.$apply();
- },
done: function (e, data) {
if (e.isDefaultPrevented()) {
return false;
@@ -197,8 +201,8 @@
// The FileUploadController initializes the fileupload widget and
// provides scope methods to control the File Upload functionality:
.controller('FileUploadController', [
- '$scope', '$element', '$attrs', '$window', 'fileUpload',
- function ($scope, $element, $attrs, $window, fileUpload) {
+ '$scope', '$element', '$attrs', '$window', 'fileUpload','$q',
+ function ($scope, $element, $attrs, $window, fileUpload, $q) {
var uploadMethods = {
progress: function () {
return $element.fileupload('progress');
@@ -260,19 +264,21 @@
$scope.applyOnQueue = function (method) {
var list = this.queue.slice(0),
i,
- file;
+ file,
+ promises = [];
for (i = 0; i < list.length; i += 1) {
file = list[i];
if (file[method]) {
- file[method]();
+ promises.push(file[method]());
}
}
+ return $q.all(promises);
};
$scope.submit = function () {
- this.applyOnQueue('$submit');
+ return this.applyOnQueue('$submit');
};
$scope.cancel = function () {
- this.applyOnQueue('$cancel');
+ return this.applyOnQueue('$cancel');
};
// Add upload methods to the scope:
angular.extend($scope, uploadMethods);
@@ -320,9 +326,11 @@
'fileuploadprocessalways',
'fileuploadprocessstop'
].join(' '), function (e, data) {
- if ($scope.$emit(e.type, data).defaultPrevented) {
- e.preventDefault();
- }
+ $scope.$parent.$applyAsync(function () {
+ if ($scope.$emit(e.type, data).defaultPrevented) {
+ e.preventDefault();
+ }
+ });
}).on('remove', function () {
// Remove upload methods from the scope,
// when the widget is removed:
diff --git a/library/blueimp_upload/js/jquery.fileupload-audio.js b/library/blueimp_upload/js/jquery.fileupload-audio.js
index 575800e82..a25377619 100644
--- a/library/blueimp_upload/js/jquery.fileupload-audio.js
+++ b/library/blueimp_upload/js/jquery.fileupload-audio.js
@@ -1,18 +1,18 @@
/*
- * jQuery File Upload Audio Preview Plugin 1.0.3
+ * jQuery File Upload Audio Preview Plugin
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2013, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
/* jshint nomen:false */
-/* global define, window, document */
+/* global define, require, window, document */
-(function (factory) {
+;(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
@@ -21,6 +21,13 @@
'load-image',
'./jquery.fileupload-process'
], factory);
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS:
+ factory(
+ require('jquery'),
+ require('blueimp-load-image/js/load-image'),
+ require('./jquery.fileupload-process')
+ );
} else {
// Browser globals:
factory(
diff --git a/library/blueimp_upload/js/jquery.fileupload-image.js b/library/blueimp_upload/js/jquery.fileupload-image.js
index 5bb7026ae..65fc6d7b8 100644
--- a/library/blueimp_upload/js/jquery.fileupload-image.js
+++ b/library/blueimp_upload/js/jquery.fileupload-image.js
@@ -1,18 +1,18 @@
/*
- * jQuery File Upload Image Preview & Resize Plugin 1.7.2
+ * jQuery File Upload Image Preview & Resize Plugin
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2013, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
/* jshint nomen:false */
-/* global define, window, Blob */
+/* global define, require, window, Blob */
-(function (factory) {
+;(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
@@ -20,11 +20,22 @@
'jquery',
'load-image',
'load-image-meta',
+ 'load-image-scale',
'load-image-exif',
- 'load-image-ios',
'canvas-to-blob',
'./jquery.fileupload-process'
], factory);
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS:
+ factory(
+ require('jquery'),
+ require('blueimp-load-image/js/load-image'),
+ require('blueimp-load-image/js/load-image-meta'),
+ require('blueimp-load-image/js/load-image-scale'),
+ require('blueimp-load-image/js/load-image-exif'),
+ require('blueimp-canvas-to-blob'),
+ require('./jquery.fileupload-process')
+ );
} else {
// Browser globals:
factory(
@@ -236,7 +247,7 @@
blob.name = file.name;
} else if (file.name) {
blob.name = file.name.replace(
- /\..+$/,
+ /\.\w+$/,
'.' + blob.type.substr(6)
);
}
diff --git a/library/blueimp_upload/js/jquery.fileupload-jquery-ui.js b/library/blueimp_upload/js/jquery.fileupload-jquery-ui.js
index af0a00b1e..7b136b379 100755..100644
--- a/library/blueimp_upload/js/jquery.fileupload-jquery-ui.js
+++ b/library/blueimp_upload/js/jquery.fileupload-jquery-ui.js
@@ -1,22 +1,31 @@
/*
- * jQuery File Upload jQuery UI Plugin 8.7.1
+ * jQuery File Upload jQuery UI Plugin
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2013, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
/* jshint nomen:false */
-/* global define, window */
+/* global define, require, window */
-(function (factory) {
+;(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
- define(['jquery', './jquery.fileupload-ui'], factory);
+ define([
+ 'jquery',
+ './jquery.fileupload-ui'
+ ], factory);
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS:
+ factory(
+ require('jquery'),
+ require('./jquery.fileupload-ui')
+ );
} else {
// Browser globals:
factory(window.jQuery);
diff --git a/library/blueimp_upload/js/jquery.fileupload-process.js b/library/blueimp_upload/js/jquery.fileupload-process.js
index 8a6b929a6..638f0d26b 100644
--- a/library/blueimp_upload/js/jquery.fileupload-process.js
+++ b/library/blueimp_upload/js/jquery.fileupload-process.js
@@ -1,18 +1,18 @@
/*
- * jQuery File Upload Processing Plugin 1.3.0
+ * jQuery File Upload Processing Plugin
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2012, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
/* jshint nomen:false */
-/* global define, window */
+/* global define, require, window */
-(function (factory) {
+;(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
@@ -20,6 +20,12 @@
'jquery',
'./jquery.fileupload'
], factory);
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS:
+ factory(
+ require('jquery'),
+ require('./jquery.fileupload')
+ );
} else {
// Browser globals:
factory(
@@ -81,7 +87,7 @@
settings
);
};
- chain = chain.pipe(func, settings.always && func);
+ chain = chain.then(func, settings.always && func);
});
chain
.done(function () {
@@ -148,7 +154,7 @@
};
opts.index = index;
that._processing += 1;
- that._processingQueue = that._processingQueue.pipe(func, func)
+ that._processingQueue = that._processingQueue.then(func, func)
.always(function () {
that._processing -= 1;
if (that._processing === 0) {
diff --git a/library/blueimp_upload/js/jquery.fileupload-ui.js b/library/blueimp_upload/js/jquery.fileupload-ui.js
index 62cf9aa38..83e7449e6 100644
--- a/library/blueimp_upload/js/jquery.fileupload-ui.js
+++ b/library/blueimp_upload/js/jquery.fileupload-ui.js
@@ -1,29 +1,38 @@
/*
- * jQuery File Upload User Interface Plugin 9.6.0
+ * jQuery File Upload User Interface Plugin
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
/* jshint nomen:false */
-/* global define, window */
+/* global define, require, window */
-(function (factory) {
+;(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
define([
'jquery',
- 'tmpl',
+ 'blueimp-tmpl',
'./jquery.fileupload-image',
'./jquery.fileupload-audio',
'./jquery.fileupload-video',
'./jquery.fileupload-validate'
], factory);
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS:
+ factory(
+ require('jquery'),
+ require('blueimp-tmpl'),
+ require('./jquery.fileupload-image'),
+ require('./jquery.fileupload-video'),
+ require('./jquery.fileupload-validate')
+ );
} else {
// Browser globals:
factory(
@@ -62,10 +71,10 @@
// The expected data type of the upload response, sets the dataType
// option of the $.ajax upload requests:
dataType: 'json',
-
+
// Error and info messages:
messages: {
- unknownError: 'Unknown error'
+ unknownError: 'Unknown error'
},
// Function returning the current number of files,
diff --git a/library/blueimp_upload/js/jquery.fileupload-validate.js b/library/blueimp_upload/js/jquery.fileupload-validate.js
index f93a18fa2..eebeb3733 100644
--- a/library/blueimp_upload/js/jquery.fileupload-validate.js
+++ b/library/blueimp_upload/js/jquery.fileupload-validate.js
@@ -1,17 +1,17 @@
/*
- * jQuery File Upload Validation Plugin 1.1.2
+ * jQuery File Upload Validation Plugin
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2013, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
-/* global define, window */
+/* global define, require, window */
-(function (factory) {
+;(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
@@ -19,6 +19,12 @@
'jquery',
'./jquery.fileupload-process'
], factory);
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS:
+ factory(
+ require('jquery'),
+ require('./jquery.fileupload-process')
+ );
} else {
// Browser globals:
factory(
@@ -33,7 +39,7 @@
{
action: 'validate',
// Always trigger this action,
- // even if the previous action was rejected:
+ // even if the previous action was rejected:
always: true,
// Options taken from the global options map:
acceptFileTypes: '@',
diff --git a/library/blueimp_upload/js/jquery.fileupload-video.js b/library/blueimp_upload/js/jquery.fileupload-video.js
index 3764b27a2..aedcec2ba 100644
--- a/library/blueimp_upload/js/jquery.fileupload-video.js
+++ b/library/blueimp_upload/js/jquery.fileupload-video.js
@@ -1,18 +1,18 @@
/*
- * jQuery File Upload Video Preview Plugin 1.0.3
+ * jQuery File Upload Video Preview Plugin
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2013, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
/* jshint nomen:false */
-/* global define, window, document */
+/* global define, require, window, document */
-(function (factory) {
+;(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
@@ -21,6 +21,13 @@
'load-image',
'./jquery.fileupload-process'
], factory);
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS:
+ factory(
+ require('jquery'),
+ require('blueimp-load-image/js/load-image'),
+ require('./jquery.fileupload-process')
+ );
} else {
// Browser globals:
factory(
diff --git a/library/blueimp_upload/js/jquery.fileupload.js b/library/blueimp_upload/js/jquery.fileupload.js
index a4cfdc0ac..5ff151b53 100644
--- a/library/blueimp_upload/js/jquery.fileupload.js
+++ b/library/blueimp_upload/js/jquery.fileupload.js
@@ -1,25 +1,31 @@
/*
- * jQuery File Upload Plugin 5.42.0
+ * jQuery File Upload Plugin
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
/* jshint nomen:false */
-/* global define, window, document, location, Blob, FormData */
+/* global define, require, window, document, location, Blob, FormData */
-(function (factory) {
+;(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
define([
'jquery',
- 'jquery.ui.widget'
+ 'jquery-ui/ui/widget'
], factory);
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS:
+ factory(
+ require('jquery'),
+ require('./vendor/jquery.ui.widget')
+ );
} else {
// Browser globals:
factory(window.jQuery);
@@ -271,7 +277,8 @@
// The following are jQuery ajax settings required for the file uploads:
processData: false,
contentType: false,
- cache: false
+ cache: false,
+ timeout: 0
},
// A list of options that require reinitializing event listeners and/or
@@ -645,7 +652,7 @@
data.process = function (resolveFunc, rejectFunc) {
if (resolveFunc || rejectFunc) {
data._processQueue = this._processQueue =
- (this._processQueue || getPromise([this])).pipe(
+ (this._processQueue || getPromise([this])).then(
function () {
if (data.errorThrown) {
return $.Deferred()
@@ -653,7 +660,7 @@
}
return getPromise(arguments);
}
- ).pipe(resolveFunc, rejectFunc);
+ ).then(resolveFunc, rejectFunc);
}
return this._processQueue || getPromise([this]);
};
@@ -938,9 +945,9 @@
if (this.options.limitConcurrentUploads > 1) {
slot = $.Deferred();
this._slots.push(slot);
- pipe = slot.pipe(send);
+ pipe = slot.then(send);
} else {
- this._sequence = this._sequence.pipe(send, send);
+ this._sequence = this._sequence.then(send, send);
pipe = this._sequence;
}
// Return the piped Promise object, enhanced with an abort method,
@@ -977,7 +984,10 @@
fileSet,
i,
j = 0;
- if (limitSize && (!filesLength || files[0].size === undefined)) {
+ if (!filesLength) {
+ return false;
+ }
+ if (limitSize && files[0].size === undefined) {
limitSize = undefined;
}
if (!(options.singleFileUploads || limit || limitSize) ||
@@ -1036,13 +1046,19 @@
_replaceFileInput: function (data) {
var input = data.fileInput,
- inputClone = input.clone(true);
+ inputClone = input.clone(true),
+ restoreFocus = input.is(document.activeElement);
// Add a reference for the new cloned file input to the data argument:
data.fileInputClone = inputClone;
$('<form></form>').append(inputClone)[0].reset();
// Detaching allows to insert the fileInput on another form
// without loosing the file input value:
input.after(inputClone).detach();
+ // If the fileInput had focus before it was detached,
+ // restore focus to the inputClone.
+ if (restoreFocus) {
+ inputClone.focus();
+ }
// Avoid memory leaks with the detached file input:
$.cleanData(input.unbind('remove'));
// Replace the original file input element in the fileInput
@@ -1064,6 +1080,8 @@
_handleFileTreeEntry: function (entry, path) {
var that = this,
dfd = $.Deferred(),
+ entries = [],
+ dirReader,
errorHandler = function (e) {
if (e && !e.entry) {
e.entry = entry;
@@ -1091,8 +1109,7 @@
readEntries();
}
}, errorHandler);
- },
- dirReader, entries = [];
+ };
path = path || '';
if (entry.isFile) {
if (entry._file) {
@@ -1123,7 +1140,7 @@
$.map(entries, function (entry) {
return that._handleFileTreeEntry(entry, path);
})
- ).pipe(function () {
+ ).then(function () {
return Array.prototype.concat.apply(
[],
arguments
@@ -1192,7 +1209,7 @@
return $.when.apply(
$,
$.map(fileInput, this._getSingleFileInputFiles)
- ).pipe(function () {
+ ).then(function () {
return Array.prototype.concat.apply(
[],
arguments
@@ -1295,6 +1312,10 @@
this._off(this.options.fileInput, 'change');
},
+ _destroy: function () {
+ this._destroyEventHandlers();
+ },
+
_setOption: function (key, value) {
var reinit = $.inArray(key, this._specialOptions) !== -1;
if (reinit) {
@@ -1338,15 +1359,19 @@
_initDataAttributes: function () {
var that = this,
options = this.options,
- clone = $(this.element[0].cloneNode(false));
+ data = this.element.data();
// Initialize options set via HTML5 data-attributes:
$.each(
- clone.data(),
- function (key, value) {
- var dataAttributeName = 'data-' +
- // Convert camelCase to hyphen-ated key:
- key.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
- if (clone.attr(dataAttributeName)) {
+ this.element[0].attributes,
+ function (index, attr) {
+ var key = attr.name.toLowerCase(),
+ value;
+ if (/^data-/.test(key)) {
+ // Convert hyphen-ated key to camelCase:
+ key = key.slice(5).replace(/-[a-z]/g, function (str) {
+ return str.charAt(1).toUpperCase();
+ });
+ value = data[key];
if (that._isRegExpOption(key, value)) {
value = that._getRegExp(value);
}
diff --git a/library/blueimp_upload/js/jquery.iframe-transport.js b/library/blueimp_upload/js/jquery.iframe-transport.js
index 8d64b591b..8d25c4641 100644
--- a/library/blueimp_upload/js/jquery.iframe-transport.js
+++ b/library/blueimp_upload/js/jquery.iframe-transport.js
@@ -1,21 +1,24 @@
/*
- * jQuery Iframe Transport Plugin 1.8.2
+ * jQuery Iframe Transport Plugin
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2011, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
-/* global define, window, document */
+/* global define, require, window, document, JSON */
-(function (factory) {
+;(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
define(['jquery'], factory);
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS:
+ factory(require('jquery'));
} else {
// Browser globals:
factory(window.jQuery);
@@ -24,7 +27,14 @@
'use strict';
// Helper variable to create unique names for the transport iframes:
- var counter = 0;
+ var counter = 0,
+ jsonAPI = $,
+ jsonParse = 'parseJSON';
+
+ if ('JSON' in window && 'parse' in JSON) {
+ jsonAPI = JSON;
+ jsonParse = 'parse';
+ }
// The iframe transport accepts four additional options:
// options.fileInput: a jQuery collection of file input fields
@@ -194,7 +204,7 @@
return iframe && $(iframe[0].body).text();
},
'iframe json': function (iframe) {
- return iframe && $.parseJSON($(iframe[0].body).text());
+ return iframe && jsonAPI[jsonParse]($(iframe[0].body).text());
},
'iframe html': function (iframe) {
return iframe && $(iframe[0].body).html();
diff --git a/library/blueimp_upload/js/main.js b/library/blueimp_upload/js/main.js
index 8f57967a3..0403682e7 100644
--- a/library/blueimp_upload/js/main.js
+++ b/library/blueimp_upload/js/main.js
@@ -1,12 +1,12 @@
/*
- * jQuery File Upload Plugin JS Example 8.9.1
+ * jQuery File Upload Plugin JS Example
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
/* global $, window */
@@ -40,7 +40,7 @@ $(function () {
// send Blob objects via XHR requests:
disableImageResize: /Android(?!.*Chrome)|Opera/
.test(window.navigator.userAgent),
- maxFileSize: 5000000,
+ maxFileSize: 999000,
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i
});
// Upload server status check for browsers with CORS support:
diff --git a/library/blueimp_upload/js/vendor/jquery.ui.widget.js b/library/blueimp_upload/js/vendor/jquery.ui.widget.js
index 7899e6bb3..e08df3fd0 100644
--- a/library/blueimp_upload/js/vendor/jquery.ui.widget.js
+++ b/library/blueimp_upload/js/vendor/jquery.ui.widget.js
@@ -1,13 +1,19 @@
-/*! jQuery UI - v1.11.1 - 2014-09-17
+/*! jQuery UI - v1.11.4+CommonJS - 2015-08-28
* http://jqueryui.com
* Includes: widget.js
-* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
(function( factory ) {
if ( typeof define === "function" && define.amd ) {
// AMD. Register as an anonymous module.
define([ "jquery" ], factory );
+
+ } else if ( typeof exports === "object" ) {
+
+ // Node/CommonJS
+ factory( require( "jquery" ) );
+
} else {
// Browser globals
@@ -15,10 +21,10 @@
}
}(function( $ ) {
/*!
- * jQuery UI Widget 1.11.1
+ * jQuery UI Widget 1.11.4
* http://jqueryui.com
*
- * Copyright 2014 jQuery Foundation and other contributors
+ * Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
@@ -42,7 +48,7 @@ $.cleanData = (function( orig ) {
}
// http://bugs.jquery.com/ticket/8235
- } catch( e ) {}
+ } catch ( e ) {}
}
orig( elems );
};
@@ -196,11 +202,6 @@ $.widget.bridge = function( name, object ) {
args = widget_slice.call( arguments, 1 ),
returnValue = this;
- // allow multiple hashes to be passed on init
- options = !isMethodCall && args.length ?
- $.widget.extend.apply( null, [ options ].concat(args) ) :
- options;
-
if ( isMethodCall ) {
this.each(function() {
var methodValue,
@@ -225,6 +226,12 @@ $.widget.bridge = function( name, object ) {
}
});
} else {
+
+ // Allow multiple hashes to be passed on init
+ if ( args.length ) {
+ options = $.widget.extend.apply( null, [ options ].concat(args) );
+ }
+
this.each(function() {
var instance = $.data( this, fullName );
if ( instance ) {
@@ -260,10 +267,6 @@ $.Widget.prototype = {
this.element = $( element );
this.uuid = widget_uuid++;
this.eventNamespace = "." + this.widgetName + this.uuid;
- this.options = $.widget.extend( {},
- this.options,
- this._getCreateOptions(),
- options );
this.bindings = $();
this.hoverable = $();
@@ -286,6 +289,11 @@ $.Widget.prototype = {
this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
}
+ this.options = $.widget.extend( {},
+ this.options,
+ this._getCreateOptions(),
+ options );
+
this._create();
this._trigger( "create", null, this._getCreateEventData() );
this._init();
@@ -448,8 +456,14 @@ $.Widget.prototype = {
},
_off: function( element, eventName ) {
- eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
+ eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
+ this.eventNamespace;
element.unbind( eventName ).undelegate( eventName );
+
+ // Clear the stack to avoid memory leaks (#10056)
+ this.bindings = $( this.bindings.not( element ).get() );
+ this.focusable = $( this.focusable.not( element ).get() );
+ this.hoverable = $( this.hoverable.not( element ).get() );
},
_delay: function( handler, delay ) {
diff --git a/library/blueimp_upload/package.json b/library/blueimp_upload/package.json
index 880574aa7..ed4d33681 100644
--- a/library/blueimp_upload/package.json
+++ b/library/blueimp_upload/package.json
@@ -1,8 +1,8 @@
{
"name": "blueimp-file-upload",
- "version": "9.8.0",
+ "version": "9.18.0",
"title": "jQuery File Upload",
- "description": "File Upload widget with multiple file selection, drag&amp;drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.",
+ "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.",
"keywords": [
"jquery",
"file",
@@ -29,26 +29,27 @@
"name": "Sebastian Tschan",
"url": "https://blueimp.net"
},
- "maintainers": [
- {
- "name": "Sebastian Tschan",
- "url": "https://blueimp.net"
- }
- ],
"repository": {
"type": "git",
"url": "git://github.com/blueimp/jQuery-File-Upload.git"
},
- "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues",
- "licenses": [
- {
- "type": "MIT",
- "url": "http://www.opensource.org/licenses/MIT"
- }
- ],
+ "license": "MIT",
+ "optionalDependencies": {
+ "blueimp-canvas-to-blob": "3.5.0",
+ "blueimp-load-image": "2.12.2",
+ "blueimp-tmpl": "3.6.0"
+ },
"devDependencies": {
- "grunt": "~0.4.5",
- "grunt-bump-build-git": "~1.1.1",
- "grunt-contrib-jshint": "~0.10.0"
- }
+ "bower-json": "0.8.1",
+ "jshint": "2.9.3"
+ },
+ "scripts": {
+ "bower-version-update": "./bower-version-update.js",
+ "lint": "jshint *.js js/*.js js/cors/*.js",
+ "test": "npm run lint",
+ "preversion": "npm test",
+ "version": "npm run bower-version-update && git add bower.json",
+ "postversion": "git push --tags origin master && npm publish"
+ },
+ "main": "js/jquery.fileupload.js"
}
diff --git a/library/blueimp_upload/server/gae-go/app/main.go b/library/blueimp_upload/server/gae-go/app/main.go
index 03af0b1d2..a92d128c0 100644
--- a/library/blueimp_upload/server/gae-go/app/main.go
+++ b/library/blueimp_upload/server/gae-go/app/main.go
@@ -1,59 +1,90 @@
/*
- * jQuery File Upload Plugin GAE Go Example 3.2.0
+ * jQuery File Upload Plugin GAE Go Example
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2011, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
package app
import (
- "appengine"
- "appengine/blobstore"
- "appengine/image"
- "appengine/taskqueue"
+ "bufio"
"bytes"
"encoding/json"
"fmt"
+ "github.com/disintegration/gift"
+ "golang.org/x/net/context"
+ "google.golang.org/appengine"
+ "google.golang.org/appengine/memcache"
+ "hash/crc32"
+ "image"
+ "image/gif"
+ "image/jpeg"
+ "image/png"
"io"
"log"
"mime/multipart"
"net/http"
"net/url"
+ "path/filepath"
"regexp"
"strings"
- "time"
)
const (
- WEBSITE = "https://blueimp.github.io/jQuery-File-Upload/"
- MIN_FILE_SIZE = 1 // bytes
- MAX_FILE_SIZE = 5000000 // bytes
+ WEBSITE = "https://blueimp.github.io/jQuery-File-Upload/"
+ MIN_FILE_SIZE = 1 // bytes
+ // Max file size is memcache limit (1MB) minus key size minus overhead:
+ MAX_FILE_SIZE = 999000 // bytes
IMAGE_TYPES = "image/(gif|p?jpeg|(x-)?png)"
ACCEPT_FILE_TYPES = IMAGE_TYPES
+ THUMB_MAX_WIDTH = 80
+ THUMB_MAX_HEIGHT = 80
EXPIRATION_TIME = 300 // seconds
- THUMBNAIL_PARAM = "=s80"
+ // If empty, only allow redirects to the referer protocol+host.
+ // Set to a regexp string for custom pattern matching:
+ REDIRECT_ALLOW_TARGET = ""
)
var (
imageTypes = regexp.MustCompile(IMAGE_TYPES)
acceptFileTypes = regexp.MustCompile(ACCEPT_FILE_TYPES)
+ thumbSuffix = "." + fmt.Sprint(THUMB_MAX_WIDTH) + "x" +
+ fmt.Sprint(THUMB_MAX_HEIGHT)
)
+func escape(s string) string {
+ return strings.Replace(url.QueryEscape(s), "+", "%20", -1)
+}
+
+func extractKey(r *http.Request) string {
+ // Use RequestURI instead of r.URL.Path, as we need the encoded form:
+ path := strings.Split(r.RequestURI, "?")[0]
+ // Also adjust double encoded slashes:
+ return strings.Replace(path[1:], "%252F", "%2F", -1)
+}
+
+func check(err error) {
+ if err != nil {
+ panic(err)
+ }
+}
+
type FileInfo struct {
- Key appengine.BlobKey `json:"-"`
- Url string `json:"url,omitempty"`
- ThumbnailUrl string `json:"thumbnailUrl,omitempty"`
- Name string `json:"name"`
- Type string `json:"type"`
- Size int64 `json:"size"`
- Error string `json:"error,omitempty"`
- DeleteUrl string `json:"deleteUrl,omitempty"`
- DeleteType string `json:"deleteType,omitempty"`
+ Key string `json:"-"`
+ ThumbnailKey string `json:"-"`
+ Url string `json:"url,omitempty"`
+ ThumbnailUrl string `json:"thumbnailUrl,omitempty"`
+ Name string `json:"name"`
+ Type string `json:"type"`
+ Size int64 `json:"size"`
+ Error string `json:"error,omitempty"`
+ DeleteUrl string `json:"deleteUrl,omitempty"`
+ DeleteType string `json:"deleteType,omitempty"`
}
func (fi *FileInfo) ValidateType() (valid bool) {
@@ -75,50 +106,58 @@ func (fi *FileInfo) ValidateSize() (valid bool) {
return false
}
-func (fi *FileInfo) CreateUrls(r *http.Request, c appengine.Context) {
+func (fi *FileInfo) CreateUrls(r *http.Request, c context.Context) {
u := &url.URL{
Scheme: r.URL.Scheme,
Host: appengine.DefaultVersionHostname(c),
Path: "/",
}
uString := u.String()
- fi.Url = uString + escape(string(fi.Key)) + "/" +
- escape(string(fi.Name))
- fi.DeleteUrl = fi.Url + "?delete=true"
+ fi.Url = uString + fi.Key
+ fi.DeleteUrl = fi.Url
fi.DeleteType = "DELETE"
- if imageTypes.MatchString(fi.Type) {
- servingUrl, err := image.ServingURL(
- c,
- fi.Key,
- &image.ServingURLOptions{
- Secure: strings.HasSuffix(u.Scheme, "s"),
- Size: 0,
- Crop: false,
- },
- )
- check(err)
- fi.ThumbnailUrl = servingUrl.String() + THUMBNAIL_PARAM
+ if fi.ThumbnailKey != "" {
+ fi.ThumbnailUrl = uString + fi.ThumbnailKey
}
}
-func check(err error) {
- if err != nil {
- panic(err)
- }
-}
-
-func escape(s string) string {
- return strings.Replace(url.QueryEscape(s), "+", "%20", -1)
+func (fi *FileInfo) SetKey(checksum uint32) {
+ fi.Key = escape(string(fi.Type)) + "/" +
+ escape(fmt.Sprint(checksum)) + "/" +
+ escape(string(fi.Name))
}
-func delayedDelete(c appengine.Context, fi *FileInfo) {
- if key := string(fi.Key); key != "" {
- task := &taskqueue.Task{
- Path: "/" + escape(key) + "/-",
- Method: "DELETE",
- Delay: time.Duration(EXPIRATION_TIME) * time.Second,
+func (fi *FileInfo) createThumb(buffer *bytes.Buffer, c context.Context) {
+ if imageTypes.MatchString(fi.Type) {
+ src, _, err := image.Decode(bytes.NewReader(buffer.Bytes()))
+ check(err)
+ filter := gift.New(gift.ResizeToFit(
+ THUMB_MAX_WIDTH,
+ THUMB_MAX_HEIGHT,
+ gift.LanczosResampling,
+ ))
+ dst := image.NewNRGBA(filter.Bounds(src.Bounds()))
+ filter.Draw(dst, src)
+ buffer.Reset()
+ bWriter := bufio.NewWriter(buffer)
+ switch fi.Type {
+ case "image/jpeg", "image/pjpeg":
+ err = jpeg.Encode(bWriter, dst, nil)
+ case "image/gif":
+ err = gif.Encode(bWriter, dst, nil)
+ default:
+ err = png.Encode(bWriter, dst)
+ }
+ check(err)
+ bWriter.Flush()
+ thumbnailKey := fi.Key + thumbSuffix + filepath.Ext(fi.Name)
+ item := &memcache.Item{
+ Key: thumbnailKey,
+ Value: buffer.Bytes(),
}
- taskqueue.Add(c, task, "")
+ err = memcache.Set(c, item)
+ check(err)
+ fi.ThumbnailKey = thumbnailKey
}
}
@@ -136,24 +175,26 @@ func handleUpload(r *http.Request, p *multipart.Part) (fi *FileInfo) {
fi.Error = rec.(error).Error()
}
}()
+ var buffer bytes.Buffer
+ hash := crc32.NewIEEE()
+ mw := io.MultiWriter(&buffer, hash)
lr := &io.LimitedReader{R: p, N: MAX_FILE_SIZE + 1}
+ _, err := io.Copy(mw, lr)
+ check(err)
+ fi.Size = MAX_FILE_SIZE + 1 - lr.N
+ if !fi.ValidateSize() {
+ return
+ }
+ fi.SetKey(hash.Sum32())
+ item := &memcache.Item{
+ Key: fi.Key,
+ Value: buffer.Bytes(),
+ }
context := appengine.NewContext(r)
- w, err := blobstore.Create(context, fi.Type)
- defer func() {
- w.Close()
- fi.Size = MAX_FILE_SIZE + 1 - lr.N
- fi.Key, err = w.Key()
- check(err)
- if !fi.ValidateSize() {
- err := blobstore.Delete(context, fi.Key)
- check(err)
- return
- }
- delayedDelete(context, fi)
- fi.CreateUrls(r, context)
- }()
+ err = memcache.Set(context, item)
check(err)
- _, err = io.Copy(w, lr)
+ fi.createThumb(&buffer, context)
+ fi.CreateUrls(r, context)
return
}
@@ -183,49 +224,70 @@ func handleUploads(r *http.Request) (fileInfos []*FileInfo) {
return
}
+func validateRedirect(r *http.Request, redirect string) bool {
+ if redirect != "" {
+ var redirectAllowTarget *regexp.Regexp
+ if REDIRECT_ALLOW_TARGET != "" {
+ redirectAllowTarget = regexp.MustCompile(REDIRECT_ALLOW_TARGET)
+ } else {
+ referer := r.Referer()
+ if referer == "" {
+ return false
+ }
+ refererUrl, err := url.Parse(referer)
+ if err != nil {
+ return false
+ }
+ redirectAllowTarget = regexp.MustCompile("^" + regexp.QuoteMeta(
+ refererUrl.Scheme+"://"+refererUrl.Host+"/",
+ ))
+ }
+ return redirectAllowTarget.MatchString(redirect)
+ }
+ return false
+}
+
func get(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
http.Redirect(w, r, WEBSITE, http.StatusFound)
return
}
- parts := strings.Split(r.URL.Path, "/")
+ // Use RequestURI instead of r.URL.Path, as we need the encoded form:
+ key := extractKey(r)
+ parts := strings.Split(key, "/")
if len(parts) == 3 {
- if key := parts[1]; key != "" {
- blobKey := appengine.BlobKey(key)
- bi, err := blobstore.Stat(appengine.NewContext(r), blobKey)
- if err == nil {
- w.Header().Add("X-Content-Type-Options", "nosniff")
- if !imageTypes.MatchString(bi.ContentType) {
- w.Header().Add("Content-Type", "application/octet-stream")
- w.Header().Add(
- "Content-Disposition",
- fmt.Sprintf("attachment; filename=\"%s\"", parts[2]),
- )
- }
- w.Header().Add(
- "Cache-Control",
- fmt.Sprintf("public,max-age=%d", EXPIRATION_TIME),
- )
- blobstore.Send(w, blobKey)
- return
+ context := appengine.NewContext(r)
+ item, err := memcache.Get(context, key)
+ if err == nil {
+ w.Header().Add("X-Content-Type-Options", "nosniff")
+ contentType, _ := url.QueryUnescape(parts[0])
+ if !imageTypes.MatchString(contentType) {
+ contentType = "application/octet-stream"
}
+ w.Header().Add("Content-Type", contentType)
+ w.Header().Add(
+ "Cache-Control",
+ fmt.Sprintf("public,max-age=%d", EXPIRATION_TIME),
+ )
+ w.Write(item.Value)
+ return
}
}
http.Error(w, "404 Not Found", http.StatusNotFound)
}
func post(w http.ResponseWriter, r *http.Request) {
- result := make(map[string][]*FileInfo, 1)
- result["files"] = handleUploads(r)
+ result := make(map[string][]*FileInfo, 1)
+ result["files"] = handleUploads(r)
b, err := json.Marshal(result)
check(err)
- if redirect := r.FormValue("redirect"); redirect != "" {
- if strings.Contains(redirect, "%s") {
- redirect = fmt.Sprintf(
- redirect,
- escape(string(b)),
- )
- }
+ if redirect := r.FormValue("redirect"); validateRedirect(r, redirect) {
+ if strings.Contains(redirect, "%s") {
+ redirect = fmt.Sprintf(
+ redirect,
+ escape(string(b)),
+ )
+ }
http.Redirect(w, r, redirect, http.StatusFound)
return
}
@@ -238,27 +300,30 @@ func post(w http.ResponseWriter, r *http.Request) {
}
func delete(w http.ResponseWriter, r *http.Request) {
- parts := strings.Split(r.URL.Path, "/")
- if len(parts) != 3 {
- return
- }
- result := make(map[string]bool, 1)
- if key := parts[1]; key != "" {
- c := appengine.NewContext(r)
- blobKey := appengine.BlobKey(key)
- err := blobstore.Delete(c, blobKey)
- check(err)
- err = image.DeleteServingURL(c, blobKey)
+ key := extractKey(r)
+ parts := strings.Split(key, "/")
+ if len(parts) == 3 {
+ result := make(map[string]bool, 1)
+ context := appengine.NewContext(r)
+ err := memcache.Delete(context, key)
+ if err == nil {
+ result[key] = true
+ contentType, _ := url.QueryUnescape(parts[0])
+ if imageTypes.MatchString(contentType) {
+ thumbnailKey := key + thumbSuffix + filepath.Ext(parts[2])
+ err := memcache.Delete(context, thumbnailKey)
+ if err == nil {
+ result[thumbnailKey] = true
+ }
+ }
+ }
+ w.Header().Set("Content-Type", "application/json")
+ b, err := json.Marshal(result)
check(err)
- result[key] = true
- }
- jsonType := "application/json"
- if strings.Index(r.Header.Get("Accept"), jsonType) != -1 {
- w.Header().Set("Content-Type", jsonType)
+ fmt.Fprintln(w, string(b))
+ } else {
+ http.Error(w, "405 Method not allowed", http.StatusMethodNotAllowed)
}
- b, err := json.Marshal(result)
- check(err)
- fmt.Fprintln(w, string(b))
}
func handle(w http.ResponseWriter, r *http.Request) {
@@ -267,15 +332,15 @@ func handle(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Access-Control-Allow-Origin", "*")
w.Header().Add(
"Access-Control-Allow-Methods",
- "OPTIONS, HEAD, GET, POST, PUT, DELETE",
+ "OPTIONS, HEAD, GET, POST, DELETE",
)
w.Header().Add(
"Access-Control-Allow-Headers",
"Content-Type, Content-Range, Content-Disposition",
)
switch r.Method {
- case "OPTIONS":
- case "HEAD":
+ case "OPTIONS", "HEAD":
+ return
case "GET":
get(w, r)
case "POST":
diff --git a/library/blueimp_upload/server/gae-python/app.yaml b/library/blueimp_upload/server/gae-python/app.yaml
index 5fe123f59..764449b74 100644
--- a/library/blueimp_upload/server/gae-python/app.yaml
+++ b/library/blueimp_upload/server/gae-python/app.yaml
@@ -4,8 +4,9 @@ runtime: python27
api_version: 1
threadsafe: true
-builtins:
-- deferred: on
+libraries:
+- name: PIL
+ version: latest
handlers:
- url: /(favicon\.ico|robots\.txt)
diff --git a/library/blueimp_upload/server/gae-python/main.py b/library/blueimp_upload/server/gae-python/main.py
index 6276be6a0..1955ac00a 100644
--- a/library/blueimp_upload/server/gae-python/main.py
+++ b/library/blueimp_upload/server/gae-python/main.py
@@ -1,49 +1,57 @@
# -*- coding: utf-8 -*-
#
-# jQuery File Upload Plugin GAE Python Example 2.2.0
+# jQuery File Upload Plugin GAE Python Example
# https://github.com/blueimp/jQuery-File-Upload
#
# Copyright 2011, Sebastian Tschan
# https://blueimp.net
#
# Licensed under the MIT license:
-# http://www.opensource.org/licenses/MIT
+# https://opensource.org/licenses/MIT
#
-from __future__ import with_statement
-from google.appengine.api import files, images
-from google.appengine.ext import blobstore, deferred
-from google.appengine.ext.webapp import blobstore_handlers
+from google.appengine.api import memcache, images
import json
+import os
import re
import urllib
import webapp2
+DEBUG=os.environ.get('SERVER_SOFTWARE', '').startswith('Dev')
WEBSITE = 'https://blueimp.github.io/jQuery-File-Upload/'
MIN_FILE_SIZE = 1 # bytes
-MAX_FILE_SIZE = 5000000 # bytes
+# Max file size is memcache limit (1MB) minus key size minus overhead:
+MAX_FILE_SIZE = 999000 # bytes
IMAGE_TYPES = re.compile('image/(gif|p?jpeg|(x-)?png)')
ACCEPT_FILE_TYPES = IMAGE_TYPES
-THUMBNAIL_MODIFICATOR = '=s80' # max width / height
+THUMB_MAX_WIDTH = 80
+THUMB_MAX_HEIGHT = 80
+THUMB_SUFFIX = '.'+str(THUMB_MAX_WIDTH)+'x'+str(THUMB_MAX_HEIGHT)+'.png'
EXPIRATION_TIME = 300 # seconds
+# If set to None, only allow redirects to the referer protocol+host.
+# Set to a regexp for custom pattern matching against the redirect value:
+REDIRECT_ALLOW_TARGET = None
+
+class CORSHandler(webapp2.RequestHandler):
+ def cors(self):
+ headers = self.response.headers
+ headers['Access-Control-Allow-Origin'] = '*'
+ headers['Access-Control-Allow-Methods'] =\
+ 'OPTIONS, HEAD, GET, POST, DELETE'
+ headers['Access-Control-Allow-Headers'] =\
+ 'Content-Type, Content-Range, Content-Disposition'
+ def initialize(self, request, response):
+ super(CORSHandler, self).initialize(request, response)
+ self.cors()
-def cleanup(blob_keys):
- blobstore.delete(blob_keys)
-
-
-class UploadHandler(webapp2.RequestHandler):
+ def json_stringify(self, obj):
+ return json.dumps(obj, separators=(',', ':'))
- def initialize(self, request, response):
- super(UploadHandler, self).initialize(request, response)
- self.response.headers['Access-Control-Allow-Origin'] = '*'
- self.response.headers[
- 'Access-Control-Allow-Methods'
- ] = 'OPTIONS, HEAD, GET, POST, PUT, DELETE'
- self.response.headers[
- 'Access-Control-Allow-Headers'
- ] = 'Content-Type, Content-Range, Content-Disposition'
+ def options(self, *args, **kwargs):
+ pass
+class UploadHandler(CORSHandler):
def validate(self, file):
if file['size'] < MIN_FILE_SIZE:
file['error'] = 'File is too small'
@@ -55,6 +63,20 @@ class UploadHandler(webapp2.RequestHandler):
return True
return False
+ def validate_redirect(self, redirect):
+ if redirect:
+ if REDIRECT_ALLOW_TARGET:
+ return REDIRECT_ALLOW_TARGET.match(redirect)
+ referer = self.request.headers['referer']
+ if referer:
+ from urlparse import urlparse
+ parts = urlparse(referer)
+ redirect_allow_target = '^' + re.escape(
+ parts.scheme + '://' + parts.netloc + '/'
+ )
+ return re.match(redirect_allow_target, redirect)
+ return False
+
def get_file_size(self, file):
file.seek(0, 2) # Seek to the end of the file
size = file.tell() # Get the position of EOF
@@ -62,64 +84,58 @@ class UploadHandler(webapp2.RequestHandler):
return size
def write_blob(self, data, info):
- blob = files.blobstore.create(
- mime_type=info['type'],
- _blobinfo_uploaded_filename=info['name']
- )
- with files.open(blob, 'a') as f:
- f.write(data)
- files.finalize(blob)
- return files.blobstore.get_blob_key(blob)
+ key = urllib.quote(info['type'].encode('utf-8'), '') +\
+ '/' + str(hash(data)) +\
+ '/' + urllib.quote(info['name'].encode('utf-8'), '')
+ try:
+ memcache.set(key, data, time=EXPIRATION_TIME)
+ except: #Failed to add to memcache
+ return (None, None)
+ thumbnail_key = None
+ if IMAGE_TYPES.match(info['type']):
+ try:
+ img = images.Image(image_data=data)
+ img.resize(
+ width=THUMB_MAX_WIDTH,
+ height=THUMB_MAX_HEIGHT
+ )
+ thumbnail_data = img.execute_transforms()
+ thumbnail_key = key + THUMB_SUFFIX
+ memcache.set(
+ thumbnail_key,
+ thumbnail_data,
+ time=EXPIRATION_TIME
+ )
+ except: #Failed to resize Image or add to memcache
+ thumbnail_key = None
+ return (key, thumbnail_key)
def handle_upload(self):
results = []
- blob_keys = []
for name, fieldStorage in self.request.POST.items():
if type(fieldStorage) is unicode:
continue
result = {}
- result['name'] = re.sub(
- r'^.*\\',
- '',
- fieldStorage.filename
- )
+ result['name'] = urllib.unquote(fieldStorage.filename)
result['type'] = fieldStorage.type
result['size'] = self.get_file_size(fieldStorage.file)
if self.validate(result):
- blob_key = str(
- self.write_blob(fieldStorage.value, result)
+ key, thumbnail_key = self.write_blob(
+ fieldStorage.value,
+ result
)
- blob_keys.append(blob_key)
- result['deleteType'] = 'DELETE'
- result['deleteUrl'] = self.request.host_url +\
- '/?key=' + urllib.quote(blob_key, '')
- if (IMAGE_TYPES.match(result['type'])):
- try:
- result['url'] = images.get_serving_url(
- blob_key,
- secure_url=self.request.host_url.startswith(
- 'https'
- )
- )
- result['thumbnailUrl'] = result['url'] +\
- THUMBNAIL_MODIFICATOR
- except: # Could not get an image serving url
- pass
- if not 'url' in result:
- result['url'] = self.request.host_url +\
- '/' + blob_key + '/' + urllib.quote(
- result['name'].encode('utf-8'), '')
+ if key is not None:
+ result['url'] = self.request.host_url + '/' + key
+ result['deleteUrl'] = result['url']
+ result['deleteType'] = 'DELETE'
+ if thumbnail_key is not None:
+ result['thumbnailUrl'] = self.request.host_url +\
+ '/' + thumbnail_key
+ else:
+ result['error'] = 'Failed to store uploaded file.'
results.append(result)
- deferred.defer(
- cleanup,
- blob_keys,
- _countdown=EXPIRATION_TIME
- )
return results
- def options(self):
- pass
-
def head(self):
pass
@@ -130,9 +146,9 @@ class UploadHandler(webapp2.RequestHandler):
if (self.request.get('_method') == 'DELETE'):
return self.delete()
result = {'files': self.handle_upload()}
- s = json.dumps(result, separators=(',', ':'))
+ s = self.json_stringify(result)
redirect = self.request.get('redirect')
- if redirect:
+ if self.validate_redirect(redirect):
return self.redirect(str(
redirect.replace('%s', urllib.quote(s, ''), 1)
))
@@ -140,31 +156,49 @@ class UploadHandler(webapp2.RequestHandler):
self.response.headers['Content-Type'] = 'application/json'
self.response.write(s)
- def delete(self):
- key = self.request.get('key') or ''
- blobstore.delete(key)
- s = json.dumps({key: True}, separators=(',', ':'))
+class FileHandler(CORSHandler):
+ def normalize(self, str):
+ return urllib.quote(urllib.unquote(str), '')
+
+ def get(self, content_type, data_hash, file_name):
+ content_type = self.normalize(content_type)
+ file_name = self.normalize(file_name)
+ key = content_type + '/' + data_hash + '/' + file_name
+ data = memcache.get(key)
+ if data is None:
+ return self.error(404)
+ # Prevent browsers from MIME-sniffing the content-type:
+ self.response.headers['X-Content-Type-Options'] = 'nosniff'
+ content_type = urllib.unquote(content_type)
+ if not IMAGE_TYPES.match(content_type):
+ # Force a download dialog for non-image types:
+ content_type = 'application/octet-stream'
+ elif file_name.endswith(THUMB_SUFFIX):
+ content_type = 'image/png'
+ self.response.headers['Content-Type'] = content_type
+ # Cache for the expiration time:
+ self.response.headers['Cache-Control'] = 'public,max-age=%d' \
+ % EXPIRATION_TIME
+ self.response.write(data)
+
+ def delete(self, content_type, data_hash, file_name):
+ content_type = self.normalize(content_type)
+ file_name = self.normalize(file_name)
+ key = content_type + '/' + data_hash + '/' + file_name
+ result = {key: memcache.delete(key)}
+ content_type = urllib.unquote(content_type)
+ if IMAGE_TYPES.match(content_type):
+ thumbnail_key = key + THUMB_SUFFIX
+ result[thumbnail_key] = memcache.delete(thumbnail_key)
if 'application/json' in self.request.headers.get('Accept'):
self.response.headers['Content-Type'] = 'application/json'
+ s = self.json_stringify(result)
self.response.write(s)
-
-class DownloadHandler(blobstore_handlers.BlobstoreDownloadHandler):
- def get(self, key, filename):
- if not blobstore.get(key):
- self.error(404)
- else:
- # Prevent browsers from MIME-sniffing the content-type:
- self.response.headers['X-Content-Type-Options'] = 'nosniff'
- # Cache for the expiration time:
- self.response.headers['Cache-Control'] = 'public,max-age=%d' % EXPIRATION_TIME
- # Send the file forcing a download dialog:
- self.send_blob(key, save_as=filename, content_type='application/octet-stream')
-
app = webapp2.WSGIApplication(
[
('/', UploadHandler),
- ('/([^/]+)/([^/]+)', DownloadHandler)
+ ('/(.+)/([^/]+)/([^/]+)', FileHandler)
],
- debug=True
+ debug=DEBUG
)
diff --git a/library/blueimp_upload/server/node/.gitignore b/library/blueimp_upload/server/node/.gitignore
deleted file mode 100644
index 9daa8247d..000000000
--- a/library/blueimp_upload/server/node/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-.DS_Store
-node_modules
diff --git a/library/blueimp_upload/server/node/package.json b/library/blueimp_upload/server/node/package.json
deleted file mode 100644
index dd38c50ca..000000000
--- a/library/blueimp_upload/server/node/package.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "name": "blueimp-file-upload-node",
- "version": "2.1.0",
- "title": "jQuery File Upload Node.js example",
- "description": "Node.js implementation example of a file upload handler for jQuery File Upload.",
- "keywords": [
- "file",
- "upload",
- "cross-domain",
- "cross-site",
- "node"
- ],
- "homepage": "https://github.com/blueimp/jQuery-File-Upload",
- "author": {
- "name": "Sebastian Tschan",
- "url": "https://blueimp.net"
- },
- "maintainers": [
- {
- "name": "Sebastian Tschan",
- "url": "https://blueimp.net"
- }
- ],
- "repository": {
- "type": "git",
- "url": "git://github.com/blueimp/jQuery-File-Upload.git"
- },
- "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues",
- "licenses": [
- {
- "type": "MIT",
- "url": "http://www.opensource.org/licenses/MIT"
- }
- ],
- "dependencies": {
- "formidable": ">=1.0.11",
- "node-static": ">=0.6.5",
- "imagemagick": ">=0.1.3"
- },
- "main": "server.js"
-}
diff --git a/library/blueimp_upload/server/node/public/files/.gitignore b/library/blueimp_upload/server/node/public/files/.gitignore
deleted file mode 100644
index d6b7ef32c..000000000
--- a/library/blueimp_upload/server/node/public/files/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*
-!.gitignore
diff --git a/library/blueimp_upload/server/node/server.js b/library/blueimp_upload/server/node/server.js
deleted file mode 100755
index 808d6ffe1..000000000
--- a/library/blueimp_upload/server/node/server.js
+++ /dev/null
@@ -1,292 +0,0 @@
-#!/usr/bin/nodejs
-/*
- * jQuery File Upload Plugin Node.js Example 2.1.2
- * https://github.com/blueimp/jQuery-File-Upload
- *
- * Copyright 2012, Sebastian Tschan
- * https://blueimp.net
- *
- * Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
- */
-
-/* jshint nomen:false */
-/* global require, __dirname, unescape, console */
-
-(function (port) {
- 'use strict';
- var path = require('path'),
- fs = require('fs'),
- // Since Node 0.8, .existsSync() moved from path to fs:
- _existsSync = fs.existsSync || path.existsSync,
- formidable = require('formidable'),
- nodeStatic = require('node-static'),
- imageMagick = require('imagemagick'),
- options = {
- tmpDir: __dirname + '/tmp',
- publicDir: __dirname + '/public',
- uploadDir: __dirname + '/public/files',
- uploadUrl: '/files/',
- maxPostSize: 11000000000, // 11 GB
- minFileSize: 1,
- maxFileSize: 10000000000, // 10 GB
- acceptFileTypes: /.+/i,
- // Files not matched by this regular expression force a download dialog,
- // to prevent executing any scripts in the context of the service domain:
- inlineFileTypes: /\.(gif|jpe?g|png)$/i,
- imageTypes: /\.(gif|jpe?g|png)$/i,
- imageVersions: {
- 'thumbnail': {
- width: 80,
- height: 80
- }
- },
- accessControl: {
- allowOrigin: '*',
- allowMethods: 'OPTIONS, HEAD, GET, POST, PUT, DELETE',
- allowHeaders: 'Content-Type, Content-Range, Content-Disposition'
- },
- /* Uncomment and edit this section to provide the service via HTTPS:
- ssl: {
- key: fs.readFileSync('/Applications/XAMPP/etc/ssl.key/server.key'),
- cert: fs.readFileSync('/Applications/XAMPP/etc/ssl.crt/server.crt')
- },
- */
- nodeStatic: {
- cache: 3600 // seconds to cache served files
- }
- },
- utf8encode = function (str) {
- return unescape(encodeURIComponent(str));
- },
- fileServer = new nodeStatic.Server(options.publicDir, options.nodeStatic),
- nameCountRegexp = /(?:(?: \(([\d]+)\))?(\.[^.]+))?$/,
- nameCountFunc = function (s, index, ext) {
- return ' (' + ((parseInt(index, 10) || 0) + 1) + ')' + (ext || '');
- },
- FileInfo = function (file) {
- this.name = file.name;
- this.size = file.size;
- this.type = file.type;
- this.deleteType = 'DELETE';
- },
- UploadHandler = function (req, res, callback) {
- this.req = req;
- this.res = res;
- this.callback = callback;
- },
- serve = function (req, res) {
- res.setHeader(
- 'Access-Control-Allow-Origin',
- options.accessControl.allowOrigin
- );
- res.setHeader(
- 'Access-Control-Allow-Methods',
- options.accessControl.allowMethods
- );
- res.setHeader(
- 'Access-Control-Allow-Headers',
- options.accessControl.allowHeaders
- );
- var handleResult = function (result, redirect) {
- if (redirect) {
- res.writeHead(302, {
- 'Location': redirect.replace(
- /%s/,
- encodeURIComponent(JSON.stringify(result))
- )
- });
- res.end();
- } else {
- res.writeHead(200, {
- 'Content-Type': req.headers.accept
- .indexOf('application/json') !== -1 ?
- 'application/json' : 'text/plain'
- });
- res.end(JSON.stringify(result));
- }
- },
- setNoCacheHeaders = function () {
- res.setHeader('Pragma', 'no-cache');
- res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate');
- res.setHeader('Content-Disposition', 'inline; filename="files.json"');
- },
- handler = new UploadHandler(req, res, handleResult);
- switch (req.method) {
- case 'OPTIONS':
- res.end();
- break;
- case 'HEAD':
- case 'GET':
- if (req.url === '/') {
- setNoCacheHeaders();
- if (req.method === 'GET') {
- handler.get();
- } else {
- res.end();
- }
- } else {
- fileServer.serve(req, res);
- }
- break;
- case 'POST':
- setNoCacheHeaders();
- handler.post();
- break;
- case 'DELETE':
- handler.destroy();
- break;
- default:
- res.statusCode = 405;
- res.end();
- }
- };
- fileServer.respond = function (pathname, status, _headers, files, stat, req, res, finish) {
- // Prevent browsers from MIME-sniffing the content-type:
- _headers['X-Content-Type-Options'] = 'nosniff';
- if (!options.inlineFileTypes.test(files[0])) {
- // Force a download dialog for unsafe file extensions:
- _headers['Content-Type'] = 'application/octet-stream';
- _headers['Content-Disposition'] = 'attachment; filename="' +
- utf8encode(path.basename(files[0])) + '"';
- }
- nodeStatic.Server.prototype.respond
- .call(this, pathname, status, _headers, files, stat, req, res, finish);
- };
- FileInfo.prototype.validate = function () {
- if (options.minFileSize && options.minFileSize > this.size) {
- this.error = 'File is too small';
- } else if (options.maxFileSize && options.maxFileSize < this.size) {
- this.error = 'File is too big';
- } else if (!options.acceptFileTypes.test(this.name)) {
- this.error = 'Filetype not allowed';
- }
- return !this.error;
- };
- FileInfo.prototype.safeName = function () {
- // Prevent directory traversal and creating hidden system files:
- this.name = path.basename(this.name).replace(/^\.+/, '');
- // Prevent overwriting existing files:
- while (_existsSync(options.uploadDir + '/' + this.name)) {
- this.name = this.name.replace(nameCountRegexp, nameCountFunc);
- }
- };
- FileInfo.prototype.initUrls = function (req) {
- if (!this.error) {
- var that = this,
- baseUrl = (options.ssl ? 'https:' : 'http:') +
- '//' + req.headers.host + options.uploadUrl;
- this.url = this.deleteUrl = baseUrl + encodeURIComponent(this.name);
- Object.keys(options.imageVersions).forEach(function (version) {
- if (_existsSync(
- options.uploadDir + '/' + version + '/' + that.name
- )) {
- that[version + 'Url'] = baseUrl + version + '/' +
- encodeURIComponent(that.name);
- }
- });
- }
- };
- UploadHandler.prototype.get = function () {
- var handler = this,
- files = [];
- fs.readdir(options.uploadDir, function (err, list) {
- list.forEach(function (name) {
- var stats = fs.statSync(options.uploadDir + '/' + name),
- fileInfo;
- if (stats.isFile() && name[0] !== '.') {
- fileInfo = new FileInfo({
- name: name,
- size: stats.size
- });
- fileInfo.initUrls(handler.req);
- files.push(fileInfo);
- }
- });
- handler.callback({files: files});
- });
- };
- UploadHandler.prototype.post = function () {
- var handler = this,
- form = new formidable.IncomingForm(),
- tmpFiles = [],
- files = [],
- map = {},
- counter = 1,
- redirect,
- finish = function () {
- counter -= 1;
- if (!counter) {
- files.forEach(function (fileInfo) {
- fileInfo.initUrls(handler.req);
- });
- handler.callback({files: files}, redirect);
- }
- };
- form.uploadDir = options.tmpDir;
- form.on('fileBegin', function (name, file) {
- tmpFiles.push(file.path);
- var fileInfo = new FileInfo(file);
- fileInfo.safeName();
- map[path.basename(file.path)] = fileInfo;
- files.push(fileInfo);
- }).on('field', function (name, value) {
- if (name === 'redirect') {
- redirect = value;
- }
- }).on('file', function (name, file) {
- var fileInfo = map[path.basename(file.path)];
- fileInfo.size = file.size;
- if (!fileInfo.validate()) {
- fs.unlink(file.path);
- return;
- }
- fs.renameSync(file.path, options.uploadDir + '/' + fileInfo.name);
- if (options.imageTypes.test(fileInfo.name)) {
- Object.keys(options.imageVersions).forEach(function (version) {
- counter += 1;
- var opts = options.imageVersions[version];
- imageMagick.resize({
- width: opts.width,
- height: opts.height,
- srcPath: options.uploadDir + '/' + fileInfo.name,
- dstPath: options.uploadDir + '/' + version + '/' +
- fileInfo.name
- }, finish);
- });
- }
- }).on('aborted', function () {
- tmpFiles.forEach(function (file) {
- fs.unlink(file);
- });
- }).on('error', function (e) {
- console.log(e);
- }).on('progress', function (bytesReceived) {
- if (bytesReceived > options.maxPostSize) {
- handler.req.connection.destroy();
- }
- }).on('end', finish).parse(handler.req);
- };
- UploadHandler.prototype.destroy = function () {
- var handler = this,
- fileName;
- if (handler.req.url.slice(0, options.uploadUrl.length) === options.uploadUrl) {
- fileName = path.basename(decodeURIComponent(handler.req.url));
- if (fileName[0] !== '.') {
- fs.unlink(options.uploadDir + '/' + fileName, function (ex) {
- Object.keys(options.imageVersions).forEach(function (version) {
- fs.unlink(options.uploadDir + '/' + version + '/' + fileName);
- });
- handler.callback({success: !ex});
- });
- return;
- }
- }
- handler.callback({success: false});
- };
- if (options.ssl) {
- require('https').createServer(options.ssl, serve).listen(port);
- } else {
- require('http').createServer(serve).listen(port);
- }
-}(8888));
diff --git a/library/blueimp_upload/server/node/tmp/.gitignore b/library/blueimp_upload/server/node/tmp/.gitignore
deleted file mode 100644
index e69de29bb..000000000
--- a/library/blueimp_upload/server/node/tmp/.gitignore
+++ /dev/null
diff --git a/library/blueimp_upload/server/php/Dockerfile b/library/blueimp_upload/server/php/Dockerfile
new file mode 100644
index 000000000..ca88d3d0d
--- /dev/null
+++ b/library/blueimp_upload/server/php/Dockerfile
@@ -0,0 +1,38 @@
+FROM php:7.0-apache
+
+# Enable the Apache Headers module:
+RUN ln -s /etc/apache2/mods-available/headers.load \
+ /etc/apache2/mods-enabled/headers.load
+
+# Enable the Apache Rewrite module:
+RUN ln -s /etc/apache2/mods-available/rewrite.load \
+ /etc/apache2/mods-enabled/rewrite.load
+
+# Install GD, Imagick and ImageMagick as image conversion options:
+RUN DEBIAN_FRONTEND=noninteractive \
+ apt-get update && apt-get install -y --no-install-recommends \
+ libpng-dev \
+ libjpeg-dev \
+ libmagickwand-dev \
+ imagemagick \
+ && pecl install \
+ imagick \
+ && docker-php-ext-enable \
+ imagick \
+ && docker-php-ext-configure \
+ gd --with-jpeg-dir=/usr/include/ \
+ && docker-php-ext-install \
+ gd \
+ # Uninstall obsolete packages:
+ && apt-get autoremove -y \
+ libpng-dev \
+ libjpeg-dev \
+ libmagickwand-dev \
+ # Remove obsolete files:
+ && apt-get clean \
+ && rm -rf \
+ /tmp/* \
+ /usr/share/doc/* \
+ /var/cache/* \
+ /var/lib/apt/lists/* \
+ /var/tmp/*
diff --git a/library/blueimp_upload/server/php/UploadHandler.php b/library/blueimp_upload/server/php/UploadHandler.php
index fb77be1d0..1380d4739 100755
--- a/library/blueimp_upload/server/php/UploadHandler.php
+++ b/library/blueimp_upload/server/php/UploadHandler.php
@@ -1,13 +1,13 @@
<?php
/*
- * jQuery File Upload Plugin PHP Class 8.1.0
+ * jQuery File Upload Plugin PHP Class
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
class UploadHandler
@@ -40,11 +40,13 @@ class UploadHandler
protected $image_objects = array();
- function __construct($options = null, $initialize = true, $error_messages = null) {
+ public function __construct($options = null, $initialize = true, $error_messages = null) {
+ $this->response = array();
$this->options = array(
- 'script_url' => $this->get_full_url().'/',
+ 'script_url' => $this->get_full_url().'/'.$this->basename($this->get_server_var('SCRIPT_NAME')),
'upload_dir' => dirname($this->get_server_var('SCRIPT_FILENAME')).'/files/',
'upload_url' => $this->get_full_url().'/files/',
+ 'input_stream' => 'php://input',
'user_dirs' => false,
'mkdir_mode' => 0755,
'param_name' => 'files',
@@ -67,6 +69,14 @@ class UploadHandler
'Content-Range',
'Content-Disposition'
),
+ // By default, allow redirects to the referer protocol+host:
+ 'redirect_allow_target' => '/^'.preg_quote(
+ parse_url($this->get_server_var('HTTP_REFERER'), PHP_URL_SCHEME)
+ .'://'
+ .parse_url($this->get_server_var('HTTP_REFERER'), PHP_URL_HOST)
+ .'/', // Trailing slash to not match subdomains by mistake
+ '/' // preg_quote delimiter param
+ ).'/',
// Enable to provide file downloads via GET requests to the PHP script:
// 1. Set to 1 to download files via readfile method through PHP
// 2. Set to 2 to send a X-Sendfile header for lighttpd/Apache
@@ -147,7 +157,8 @@ class UploadHandler
'max_width' => 80,
'max_height' => 80
)
- )
+ ),
+ 'print_response' => true
);
if ($options) {
$this->options = $options + $this->options;
@@ -167,15 +178,15 @@ class UploadHandler
$this->head();
break;
case 'GET':
- $this->get();
+ $this->get($this->options['print_response']);
break;
case 'PATCH':
case 'PUT':
case 'POST':
- $this->post();
+ $this->post($this->options['print_response']);
break;
case 'DELETE':
- $this->delete();
+ $this->delete($this->options['print_response']);
break;
default:
$this->header('HTTP/1.1 405 Method Not Allowed');
@@ -300,7 +311,7 @@ class UploadHandler
$this->get_upload_path($file_name)
);
$file->url = $this->get_download_url($file->name);
- foreach($this->options['image_versions'] as $version => $options) {
+ foreach ($this->options['image_versions'] as $version => $options) {
if (!empty($version)) {
if (is_file($this->get_upload_path($file_name, $version))) {
$file->{$version.'Url'} = $this->get_download_url(
@@ -332,14 +343,15 @@ class UploadHandler
}
protected function get_error_message($error) {
- return array_key_exists($error, $this->error_messages) ?
+ return isset($this->error_messages[$error]) ?
$this->error_messages[$error] : $error;
}
- function get_config_bytes($val) {
+ public function get_config_bytes($val) {
$val = trim($val);
$last = strtolower($val[strlen($val)-1]);
- switch($last) {
+ $val = (int)$val;
+ switch ($last) {
case 'g':
$val *= 1024;
case 'm':
@@ -355,9 +367,9 @@ class UploadHandler
$file->error = $this->get_error_message($error);
return false;
}
- $content_length = $this->fix_integer_overflow(intval(
- $this->get_server_var('CONTENT_LENGTH')
- ));
+ $content_length = $this->fix_integer_overflow(
+ (int)$this->get_server_var('CONTENT_LENGTH')
+ );
$post_max_size = $this->get_config_bytes(ini_get('post_max_size'));
if ($post_max_size && ($content_length > $post_max_size)) {
$file->error = $this->get_error_message('post_max_size');
@@ -398,6 +410,21 @@ class UploadHandler
if (($max_width || $max_height || $min_width || $min_height)
&& preg_match($this->options['image_file_types'], $file->name)) {
list($img_width, $img_height) = $this->get_image_size($uploaded_file);
+
+ // If we are auto rotating the image by default, do the checks on
+ // the correct orientation
+ if (
+ @$this->options['image_versions']['']['auto_orient'] &&
+ function_exists('exif_read_data') &&
+ ($exif = @exif_read_data($uploaded_file)) &&
+ (((int) @$exif['Orientation']) >= 5)
+ ) {
+ $tmp = $img_width;
+ $img_width = $img_height;
+ $img_height = $tmp;
+ unset($tmp);
+ }
+
}
if (!empty($img_width)) {
if ($max_width && $img_width > $max_width) {
@@ -421,7 +448,7 @@ class UploadHandler
}
protected function upcount_name_callback($matches) {
- $index = isset($matches[1]) ? intval($matches[1]) + 1 : 1;
+ $index = isset($matches[1]) ? ((int)$matches[1]) + 1 : 1;
$ext = isset($matches[2]) ? $matches[2] : '';
return ' ('.$index.')'.$ext;
}
@@ -441,8 +468,8 @@ class UploadHandler
$name = $this->upcount_name($name);
}
// Keep an existing filename if this is part of a chunked upload:
- $uploaded_bytes = $this->fix_integer_overflow(intval($content_range[1]));
- while(is_file($this->get_upload_path($name))) {
+ $uploaded_bytes = $this->fix_integer_overflow((int)$content_range[1]);
+ while (is_file($this->get_upload_path($name))) {
if ($uploaded_bytes === $this->get_file_size(
$this->get_upload_path($name))) {
break;
@@ -461,7 +488,7 @@ class UploadHandler
}
if ($this->options['correct_image_extensions'] &&
function_exists('exif_imagetype')) {
- switch(@exif_imagetype($file_path)){
+ switch (@exif_imagetype($file_path)){
case IMAGETYPE_JPEG:
$extensions = array('jpg', 'jpeg');
break;
@@ -491,7 +518,7 @@ class UploadHandler
// Remove path information and dots around the filename, to prevent uploading
// into different directories or replacing hidden system files.
// Also remove control characters and spaces (\x00..\x20) around the filename:
- $name = trim(basename(stripslashes($name)), ".\x00..\x20");
+ $name = trim($this->basename(stripslashes($name)), ".\x00..\x20");
// Use a timestamp for empty filenames:
if (!$name) {
$name = str_replace('.', '-', microtime(true));
@@ -515,10 +542,6 @@ class UploadHandler
);
}
- protected function handle_form_data($file, $index) {
- // Handle form data, e.g. $_REQUEST['description'][$index]
- }
-
protected function get_scaled_image_file_paths($file_name, $version) {
$file_path = $this->get_upload_path($file_name);
if (!empty($version)) {
@@ -601,7 +624,7 @@ class UploadHandler
if ($exif === false) {
return false;
}
- $orientation = intval(@$exif['Orientation']);
+ $orientation = (int)@$exif['Orientation'];
if ($orientation < 2 || $orientation > 8) {
return false;
}
@@ -825,7 +848,7 @@ class UploadHandler
$this->get_scaled_image_file_paths($file_name, $version);
$image = $this->imagick_get_image_object(
$file_path,
- !empty($options['no_cache'])
+ !empty($options['crop']) || !empty($options['no_cache'])
);
if ($image->getImageFormat() === 'GIF') {
// Handle animated GIFs:
@@ -955,7 +978,7 @@ class UploadHandler
return $dimensions;
}
return false;
- } catch (Exception $e) {
+ } catch (\Exception $e) {
error_log($e->getMessage());
}
}
@@ -965,7 +988,7 @@ class UploadHandler
exec($cmd, $output, $error);
if (!$error && !empty($output)) {
// image.jpg JPEG 1920x1080 1920x1080+0+0 8-bit sRGB 465KB 0.000u 0:00.000
- $infos = preg_split('/\s+/', $output[0]);
+ $infos = preg_split('/\s+/', substr($output[0], strlen($file_path)));
$dimensions = preg_split('/x/', $infos[2]);
return $dimensions;
}
@@ -1008,7 +1031,7 @@ class UploadHandler
protected function handle_image_file($file_path, $file) {
$failed_versions = array();
- foreach($this->options['image_versions'] as $version => $options) {
+ foreach ($this->options['image_versions'] as $version => $options) {
if ($this->create_scaled_image($file->name, $version, $options)) {
if (!empty($version)) {
$file->{$version.'Url'} = $this->get_download_url(
@@ -1024,7 +1047,7 @@ class UploadHandler
}
if (count($failed_versions)) {
$file->error = $this->get_error_message('image_resize')
- .' ('.implode($failed_versions,', ').')';
+ .' ('.implode($failed_versions, ', ').')';
}
// Free memory:
$this->destroy_image_object($file_path);
@@ -1035,7 +1058,7 @@ class UploadHandler
$file = new \stdClass();
$file->name = $this->get_file_name($uploaded_file, $name, $size, $type, $error,
$index, $content_range);
- $file->size = $this->fix_integer_overflow(intval($size));
+ $file->size = $this->fix_integer_overflow((int)$size);
$file->type = $type;
if ($this->validate($uploaded_file, $file, $error, $index)) {
$this->handle_form_data($file, $index);
@@ -1061,7 +1084,7 @@ class UploadHandler
// Non-multipart uploads (PUT method support)
file_put_contents(
$file_path,
- fopen('php://input', 'r'),
+ fopen($this->options['input_stream'], 'r'),
$append_file ? FILE_APPEND : 0
);
}
@@ -1102,41 +1125,33 @@ class UploadHandler
protected function body($str) {
echo $str;
}
-
+
protected function header($str) {
header($str);
}
+ protected function get_upload_data($id) {
+ return @$_FILES[$id];
+ }
+
+ protected function get_post_param($id) {
+ return @$_POST[$id];
+ }
+
+ protected function get_query_param($id) {
+ return @$_GET[$id];
+ }
+
protected function get_server_var($id) {
- return isset($_SERVER[$id]) ? $_SERVER[$id] : '';
+ return @$_SERVER[$id];
}
- protected function generate_response($content, $print_response = true) {
- if ($print_response) {
- $json = json_encode($content);
- $redirect = isset($_REQUEST['redirect']) ?
- stripslashes($_REQUEST['redirect']) : null;
- if ($redirect) {
- $this->header('Location: '.sprintf($redirect, rawurlencode($json)));
- return;
- }
- $this->head();
- if ($this->get_server_var('HTTP_CONTENT_RANGE')) {
- $files = isset($content[$this->options['param_name']]) ?
- $content[$this->options['param_name']] : null;
- if ($files && is_array($files) && is_object($files[0]) && $files[0]->size) {
- $this->header('Range: 0-'.(
- $this->fix_integer_overflow(intval($files[0]->size)) - 1
- ));
- }
- }
- $this->body($json);
- }
- return $content;
+ protected function handle_form_data($file, $index) {
+ // Handle form data, e.g. $_POST['description'][$index]
}
protected function get_version_param() {
- return isset($_GET['version']) ? basename(stripslashes($_GET['version'])) : null;
+ return $this->basename(stripslashes($this->get_query_param('version')));
}
protected function get_singular_param_name() {
@@ -1145,14 +1160,16 @@ class UploadHandler
protected function get_file_name_param() {
$name = $this->get_singular_param_name();
- return isset($_REQUEST[$name]) ? basename(stripslashes($_REQUEST[$name])) : null;
+ return $this->basename(stripslashes($this->get_query_param($name)));
}
protected function get_file_names_params() {
- $params = isset($_REQUEST[$this->options['param_name']]) ?
- $_REQUEST[$this->options['param_name']] : array();
+ $params = $this->get_query_param($this->options['param_name']);
+ if (!$params) {
+ return null;
+ }
foreach ($params as $key => $value) {
- $params[$key] = basename(stripslashes($value));
+ $params[$key] = $this->basename(stripslashes($value));
}
return $params;
}
@@ -1232,6 +1249,34 @@ class UploadHandler
.implode(', ', $this->options['access_control_allow_headers']));
}
+ public function generate_response($content, $print_response = true) {
+ $this->response = $content;
+ if ($print_response) {
+ $json = json_encode($content);
+ $redirect = stripslashes($this->get_post_param('redirect'));
+ if ($redirect && preg_match($this->options['redirect_allow_target'], $redirect)) {
+ $this->header('Location: '.sprintf($redirect, rawurlencode($json)));
+ return;
+ }
+ $this->head();
+ if ($this->get_server_var('HTTP_CONTENT_RANGE')) {
+ $files = isset($content[$this->options['param_name']]) ?
+ $content[$this->options['param_name']] : null;
+ if ($files && is_array($files) && is_object($files[0]) && $files[0]->size) {
+ $this->header('Range: 0-'.(
+ $this->fix_integer_overflow((int)$files[0]->size) - 1
+ ));
+ }
+ }
+ $this->body($json);
+ }
+ return $content;
+ }
+
+ public function get_response () {
+ return $this->response;
+ }
+
public function head() {
$this->header('Pragma: no-cache');
$this->header('Cache-Control: no-store, no-cache, must-revalidate');
@@ -1245,7 +1290,7 @@ class UploadHandler
}
public function get($print_response = true) {
- if ($print_response && isset($_GET['download'])) {
+ if ($print_response && $this->get_query_param('download')) {
return $this->download();
}
$file_name = $this->get_file_name_param();
@@ -1262,58 +1307,59 @@ class UploadHandler
}
public function post($print_response = true) {
- if (isset($_REQUEST['_method']) && $_REQUEST['_method'] === 'DELETE') {
+ if ($this->get_query_param('_method') === 'DELETE') {
return $this->delete($print_response);
}
- $upload = isset($_FILES[$this->options['param_name']]) ?
- $_FILES[$this->options['param_name']] : null;
+ $upload = $this->get_upload_data($this->options['param_name']);
// Parse the Content-Disposition header, if available:
- $file_name = $this->get_server_var('HTTP_CONTENT_DISPOSITION') ?
+ $content_disposition_header = $this->get_server_var('HTTP_CONTENT_DISPOSITION');
+ $file_name = $content_disposition_header ?
rawurldecode(preg_replace(
'/(^[^"]+")|("$)/',
'',
- $this->get_server_var('HTTP_CONTENT_DISPOSITION')
+ $content_disposition_header
)) : null;
// Parse the Content-Range header, which has the following form:
// Content-Range: bytes 0-524287/2000000
- $content_range = $this->get_server_var('HTTP_CONTENT_RANGE') ?
- preg_split('/[^0-9]+/', $this->get_server_var('HTTP_CONTENT_RANGE')) : null;
+ $content_range_header = $this->get_server_var('HTTP_CONTENT_RANGE');
+ $content_range = $content_range_header ?
+ preg_split('/[^0-9]+/', $content_range_header) : null;
$size = $content_range ? $content_range[3] : null;
$files = array();
- if ($upload && is_array($upload['tmp_name'])) {
- // param_name is an array identifier like "files[]",
- // $_FILES is a multi-dimensional array:
- foreach ($upload['tmp_name'] as $index => $value) {
+ if ($upload) {
+ if (is_array($upload['tmp_name'])) {
+ // param_name is an array identifier like "files[]",
+ // $upload is a multi-dimensional array:
+ foreach ($upload['tmp_name'] as $index => $value) {
+ $files[] = $this->handle_file_upload(
+ $upload['tmp_name'][$index],
+ $file_name ? $file_name : $upload['name'][$index],
+ $size ? $size : $upload['size'][$index],
+ $upload['type'][$index],
+ $upload['error'][$index],
+ $index,
+ $content_range
+ );
+ }
+ } else {
+ // param_name is a single object identifier like "file",
+ // $upload is a one-dimensional array:
$files[] = $this->handle_file_upload(
- $upload['tmp_name'][$index],
- $file_name ? $file_name : $upload['name'][$index],
- $size ? $size : $upload['size'][$index],
- $upload['type'][$index],
- $upload['error'][$index],
- $index,
+ isset($upload['tmp_name']) ? $upload['tmp_name'] : null,
+ $file_name ? $file_name : (isset($upload['name']) ?
+ $upload['name'] : null),
+ $size ? $size : (isset($upload['size']) ?
+ $upload['size'] : $this->get_server_var('CONTENT_LENGTH')),
+ isset($upload['type']) ?
+ $upload['type'] : $this->get_server_var('CONTENT_TYPE'),
+ isset($upload['error']) ? $upload['error'] : null,
+ null,
$content_range
);
}
- } else {
- // param_name is a single object identifier like "file",
- // $_FILES is a one-dimensional array:
- $files[] = $this->handle_file_upload(
- isset($upload['tmp_name']) ? $upload['tmp_name'] : null,
- $file_name ? $file_name : (isset($upload['name']) ?
- $upload['name'] : null),
- $size ? $size : (isset($upload['size']) ?
- $upload['size'] : $this->get_server_var('CONTENT_LENGTH')),
- isset($upload['type']) ?
- $upload['type'] : $this->get_server_var('CONTENT_TYPE'),
- isset($upload['error']) ? $upload['error'] : null,
- null,
- $content_range
- );
}
- return $this->generate_response(
- array($this->options['param_name'] => $files),
- $print_response
- );
+ $response = array($this->options['param_name'] => $files);
+ return $this->generate_response($response, $print_response);
}
public function delete($print_response = true) {
@@ -1322,11 +1368,11 @@ class UploadHandler
$file_names = array($this->get_file_name_param());
}
$response = array();
- foreach($file_names as $file_name) {
+ foreach ($file_names as $file_name) {
$file_path = $this->get_upload_path($file_name);
$success = is_file($file_path) && $file_name[0] !== '.' && unlink($file_path);
if ($success) {
- foreach($this->options['image_versions'] as $version => $options) {
+ foreach ($this->options['image_versions'] as $version => $options) {
if (!empty($version)) {
$file = $this->get_upload_path($file_name, $version);
if (is_file($file)) {
@@ -1340,4 +1386,8 @@ class UploadHandler
return $this->generate_response($response, $print_response);
}
+ protected function basename($filepath, $suffix = null) {
+ $splited = preg_split('/\//', rtrim ($filepath, '/ '));
+ return substr(basename('X'.$splited[count($splited)-1], $suffix), 1);
+ }
}
diff --git a/library/blueimp_upload/server/php/docker-compose.yml b/library/blueimp_upload/server/php/docker-compose.yml
new file mode 100644
index 000000000..691ea9caa
--- /dev/null
+++ b/library/blueimp_upload/server/php/docker-compose.yml
@@ -0,0 +1,6 @@
+apache:
+ build: ./
+ ports:
+ - "80:80"
+ volumes:
+ - "../../:/var/www/html"
diff --git a/library/blueimp_upload/server/php/files/.htaccess b/library/blueimp_upload/server/php/files/.htaccess
index 56689f0bb..6f454afb9 100644
--- a/library/blueimp_upload/server/php/files/.htaccess
+++ b/library/blueimp_upload/server/php/files/.htaccess
@@ -1,8 +1,16 @@
-# The following directives force the content-type application/octet-stream
-# and force browsers to display a download dialog for non-image files.
-# This prevents the execution of script files in the context of the website:
+# To enable the Headers module, execute the following command and reload Apache:
+# sudo a2enmod headers
+
+# The following directives prevent the execution of script files
+# in the context of the website.
+# They also force the content-type application/octet-stream and
+# force browsers to display a download dialog for non-image files.
+SetHandler default-handler
ForceType application/octet-stream
Header set Content-Disposition attachment
+
+# The following unsets the forced type and Content-Disposition headers
+# for known image files:
<FilesMatch "(?i)\.(gif|jpe?g|png)$">
ForceType none
Header unset Content-Disposition
diff --git a/library/blueimp_upload/server/php/index.php b/library/blueimp_upload/server/php/index.php
index 3ae1295ef..6caabb710 100644
--- a/library/blueimp_upload/server/php/index.php
+++ b/library/blueimp_upload/server/php/index.php
@@ -1,13 +1,13 @@
<?php
/*
- * jQuery File Upload Plugin PHP Example 5.14
+ * jQuery File Upload Plugin PHP Example
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
error_reporting(E_ALL | E_STRICT);
diff --git a/library/blueimp_upload/test/index.html b/library/blueimp_upload/test/index.html
index a04e53433..4a9a6f328 100644
--- a/library/blueimp_upload/test/index.html
+++ b/library/blueimp_upload/test/index.html
@@ -1,14 +1,14 @@
<!DOCTYPE HTML>
<!--
/*
- * jQuery File Upload Plugin Test 9.1.0
+ * jQuery File Upload Plugin Test
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
-->
<html lang="en">
@@ -20,7 +20,7 @@
<meta charset="utf-8">
<title>jQuery File Upload Plugin Test</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
-<link rel="stylesheet" href="http://codeorigin.jquery.com/qunit/qunit-1.14.0.css">
+<link rel="stylesheet" href="//codeorigin.jquery.com/qunit/qunit-1.14.0.css">
</head>
<body>
<h1 id="qunit-header">jQuery File Upload Plugin Test</h1>
@@ -36,20 +36,20 @@
<div class="col-lg-7">
<!-- The fileinput-button span is used to style the file input field as button -->
<span class="btn btn-success fileinput-button">
- <i class="fa-plus fa fa-inverse"></i>
+ <i class="icon-plus icon-white"></i>
<span>Add files...</span>
<input type="file" name="files[]" multiple>
</span>
<button type="submit" class="btn btn-primary start">
- <i class="fa-arrow-circle-o-up fa fa-inverse"></i>
+ <i class="icon-upload icon-white"></i>
<span>Start upload</span>
</button>
<button type="reset" class="btn btn-warning cancel">
- <i class="fa-ban fa fa-inverse"></i>
+ <i class="icon-ban-circle icon-white"></i>
<span>Cancel upload</span>
</button>
<button type="button" class="btn btn-danger delete">
- <i class="fa-trash-o fa fa-inverse"></i>
+ <i class="icon-trash icon-white"></i>
<span>Delete</span>
</button>
<input type="checkbox" class="toggle">
@@ -168,5 +168,5 @@ window.testUIWidget = $.blueimp.fileupload;
</script>
<script src="//code.jquery.com/qunit/qunit-1.15.0.js"></script>
<script src="test.js"></script>
-</body>
+</body>
</html>
diff --git a/library/blueimp_upload/test/test.js b/library/blueimp_upload/test/test.js
index 72d08d99e..452127567 100644
--- a/library/blueimp_upload/test/test.js
+++ b/library/blueimp_upload/test/test.js
@@ -1,12 +1,12 @@
/*
- * jQuery File Upload Plugin Test 9.4.0
+ * jQuery File Upload Plugin Test
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
+ * https://opensource.org/licenses/MIT
*/
/* global $, QUnit, window, document, expect, module, test, asyncTest, start, ok, strictEqual, notStrictEqual */
@@ -83,7 +83,7 @@ $(function () {
});
test('Paste zone initialization', function () {
- ok($('#fileupload').fileupload()
+ ok($('#fileupload').fileupload({pasteZone: document})
.fileupload('option', 'pasteZone').length);
});
@@ -98,6 +98,7 @@ $(function () {
}
},
fu = $('#fileupload').fileupload({
+ pasteZone: document,
dragover: function () {
ok(true, 'Triggers dragover callback');
return false;
@@ -135,6 +136,7 @@ $(function () {
}
},
options = {
+ pasteZone: document,
dragover: function () {
ok(true, 'Triggers dragover callback');
return false;
@@ -178,6 +180,7 @@ $(function () {
}
},
fu = $('#fileupload').fileupload({
+ pasteZone: document,
dragover: function () {
ok(true, 'Triggers dragover callback');
return false;
@@ -221,6 +224,7 @@ $(function () {
}
},
fu = $('#fileupload').fileupload({
+ pasteZone: document,
dragover: function () {
ok(true, 'Triggers dragover callback');
return false;
diff --git a/library/bootstrap/css/bootstrap-reboot.css.map b/library/bootstrap/css/bootstrap-reboot.css.map
index 6a3843f99..1b90c33f3 100644
--- a/library/bootstrap/css/bootstrap-reboot.css.map
+++ b/library/bootstrap/css/bootstrap-reboot.css.map
@@ -1 +1 @@
-{"version":3,"sources":["../../scss/_reboot.scss","bootstrap-reboot.css","../../scss/_variables.scss","../../scss/mixins/_hover.scss"],"names":[],"mappings":"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","file":"bootstrap-reboot.css","sourcesContent":[null,"html {\n box-sizing: border-box;\n font-family: sans-serif;\n line-height: 1.15;\n -webkit-text-size-adjust: 100%;\n -ms-text-size-adjust: 100%;\n -ms-overflow-style: scrollbar;\n -webkit-tap-highlight-color: transparent;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: inherit;\n}\n\n@-ms-viewport {\n width: device-width;\n}\n\narticle, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {\n display: block;\n}\n\nbody {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n font-size: 1rem;\n font-weight: normal;\n line-height: 1.5;\n color: #212529;\n background-color: #fff;\n}\n\n[tabindex=\"-1\"]:focus {\n outline: none !important;\n}\n\nhr {\n box-sizing: content-box;\n height: 0;\n overflow: visible;\n}\n\nh1, h2, h3, h4, h5, h6 {\n margin-top: 0;\n margin-bottom: .5rem;\n}\n\np {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nabbr[title],\nabbr[data-original-title] {\n text-decoration: underline;\n text-decoration: underline dotted;\n cursor: help;\n border-bottom: 0;\n}\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: bold;\n}\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0;\n}\n\nblockquote {\n margin: 0 0 1rem;\n}\n\ndfn {\n font-style: italic;\n}\n\nb,\nstrong {\n font-weight: bolder;\n}\n\nsmall {\n font-size: 80%;\n}\n\nsub,\nsup {\n position: relative;\n font-size: 75%;\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -.25em;\n}\n\nsup {\n top: -.5em;\n}\n\na {\n color: #007bff;\n text-decoration: none;\n background-color: transparent;\n -webkit-text-decoration-skip: objects;\n}\n\na:hover {\n color: #0056b3;\n text-decoration: underline;\n}\n\na:not([href]):not([tabindex]) {\n color: inherit;\n text-decoration: none;\n}\n\na:not([href]):not([tabindex]):focus, a:not([href]):not([tabindex]):hover {\n color: inherit;\n text-decoration: none;\n}\n\na:not([href]):not([tabindex]):focus {\n outline: 0;\n}\n\npre,\ncode,\nkbd,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\n\npre {\n margin-top: 0;\n margin-bottom: 1rem;\n overflow: auto;\n}\n\nfigure {\n margin: 0 0 1rem;\n}\n\nimg {\n vertical-align: middle;\n border-style: none;\n}\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\na,\narea,\nbutton,\n[role=\"button\"],\ninput,\nlabel,\nselect,\nsummary,\ntextarea {\n touch-action: manipulation;\n}\n\ntable {\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: 0.75rem;\n padding-bottom: 0.75rem;\n color: #868e96;\n text-align: left;\n caption-side: bottom;\n}\n\nth {\n text-align: left;\n}\n\nlabel {\n display: inline-block;\n margin-bottom: .5rem;\n}\n\nbutton:focus {\n outline: 1px dotted;\n outline: 5px auto -webkit-focus-ring-color;\n}\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\nbutton,\ninput {\n overflow: visible;\n}\n\nbutton,\nselect {\n text-transform: none;\n}\n\nbutton,\nhtml [type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button;\n}\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n box-sizing: border-box;\n padding: 0;\n}\n\ninput[type=\"date\"],\ninput[type=\"time\"],\ninput[type=\"datetime-local\"],\ninput[type=\"month\"] {\n -webkit-appearance: listbox;\n}\n\ntextarea {\n overflow: auto;\n resize: vertical;\n}\n\nfieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n max-width: 100%;\n padding: 0;\n margin-bottom: .5rem;\n font-size: 1.5rem;\n line-height: inherit;\n color: inherit;\n white-space: normal;\n}\n\nprogress {\n vertical-align: baseline;\n}\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n[type=\"search\"] {\n outline-offset: -2px;\n -webkit-appearance: none;\n}\n\n[type=\"search\"]::-webkit-search-cancel-button,\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n::-webkit-file-upload-button {\n font: inherit;\n -webkit-appearance: button;\n}\n\noutput {\n display: inline-block;\n}\n\nsummary {\n display: list-item;\n}\n\ntemplate {\n display: none;\n}\n\n[hidden] {\n display: none !important;\n}\n\n/*# sourceMappingURL=bootstrap-reboot.css.map */",null,null]} \ No newline at end of file
+{"version":3,"sources":["../../scss/_reboot.scss","bootstrap-reboot.css","../../scss/_variables.scss","../../scss/mixins/_hover.scss"],"names":[],"mappings":"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","file":"bootstrap-reboot.css","sourcesContent":[null,"html {\n box-sizing: border-box;\n font-family: sans-serif;\n line-height: 1.15;\n -webkit-text-size-adjust: 100%;\n -ms-text-size-adjust: 100%;\n -ms-overflow-style: scrollbar;\n -webkit-tap-highlight-color: transparent;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: inherit;\n}\n\n@-ms-viewport {\n width: device-width;\n}\n\narticle, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {\n display: block;\n}\n\nbody {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n font-size: 1rem;\n font-weight: normal;\n line-height: 1.5;\n color: #212529;\n background-color: #fff;\n}\n\n[tabindex=\"-1\"]:focus {\n outline: none !important;\n}\n\nhr {\n box-sizing: content-box;\n height: 0;\n overflow: visible;\n}\n\nh1, h2, h3, h4, h5, h6 {\n margin-top: 0;\n margin-bottom: .5rem;\n}\n\np {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nabbr[title],\nabbr[data-original-title] {\n text-decoration: underline;\n text-decoration: underline dotted;\n cursor: help;\n border-bottom: 0;\n}\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: bold;\n}\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0;\n}\n\nblockquote {\n margin: 0 0 1rem;\n}\n\ndfn {\n font-style: italic;\n}\n\nb,\nstrong {\n font-weight: bolder;\n}\n\nsmall {\n font-size: 80%;\n}\n\nsub,\nsup {\n position: relative;\n font-size: 75%;\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -.25em;\n}\n\nsup {\n top: -.5em;\n}\n\na {\n color: #007bff;\n text-decoration: none;\n background-color: transparent;\n -webkit-text-decoration-skip: objects;\n}\n\na:hover {\n color: #0056b3;\n text-decoration: underline;\n}\n\na:not([href]):not([tabindex]) {\n color: inherit;\n text-decoration: none;\n}\n\na:not([href]):not([tabindex]):focus, a:not([href]):not([tabindex]):hover {\n color: inherit;\n text-decoration: none;\n}\n\na:not([href]):not([tabindex]):focus {\n outline: 0;\n}\n\npre,\ncode,\nkbd,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\n\npre {\n margin-top: 0;\n margin-bottom: 1rem;\n overflow: auto;\n}\n\nfigure {\n margin: 0 0 1rem;\n}\n\nimg {\n vertical-align: middle;\n border-style: none;\n}\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\na,\narea,\nbutton,\n[role=\"button\"],\ninput,\nlabel,\nselect,\nsummary,\ntextarea {\n touch-action: manipulation;\n}\n\ntable {\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: 0.75rem;\n padding-bottom: 0.75rem;\n color: #868e96;\n text-align: left;\n caption-side: bottom;\n}\n\nth {\n text-align: left;\n}\n\nlabel {\n display: inline-block;\n margin-bottom: .5rem;\n}\n\nbutton:focus {\n outline: 1px dotted;\n outline: 5px auto -webkit-focus-ring-color;\n}\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\nbutton,\ninput {\n overflow: visible;\n}\n\nbutton,\nselect {\n text-transform: none;\n}\n\nbutton,\nhtml [type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button;\n}\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n box-sizing: border-box;\n padding: 0;\n}\n\ninput[type=\"date\"],\ninput[type=\"time\"],\ninput[type=\"datetime-local\"],\ninput[type=\"month\"] {\n -webkit-appearance: listbox;\n}\n\ntextarea {\n overflow: auto;\n resize: vertical;\n}\n\nfieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n max-width: 100%;\n padding: 0;\n margin-bottom: .5rem;\n font-size: 1.5rem;\n line-height: inherit;\n color: inherit;\n white-space: normal;\n}\n\nprogress {\n vertical-align: baseline;\n}\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n[type=\"search\"] {\n outline-offset: -2px;\n -webkit-appearance: none;\n}\n\n[type=\"search\"]::-webkit-search-cancel-button,\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n::-webkit-file-upload-button {\n font: inherit;\n -webkit-appearance: button;\n}\n\noutput {\n display: inline-block;\n}\n\nsummary {\n display: list-item;\n}\n\ntemplate {\n display: none;\n}\n\n[hidden] {\n display: none !important;\n}\n\n/*# sourceMappingURL=bootstrap-reboot.css.map */",null,null]} \ No newline at end of file
diff --git a/library/bootstrap/css/bootstrap.css b/library/bootstrap/css/bootstrap.css
index c7679a5c5..25c1dd8ca 100644
--- a/library/bootstrap/css/bootstrap.css
+++ b/library/bootstrap/css/bootstrap.css
@@ -1496,6 +1496,21 @@ pre code {
background-color: #b9bbbe;
}
+.table-active,
+.table-active > th,
+.table-active > td {
+ background-color: rgba(0, 0, 0, 0.075);
+}
+
+.table-hover .table-active:hover {
+ background-color: rgba(0, 0, 0, 0.075);
+}
+
+.table-hover .table-active:hover > td,
+.table-hover .table-active:hover > th {
+ background-color: rgba(0, 0, 0, 0.075);
+}
+
.thead-inverse th {
color: #fff;
background-color: #212529;
@@ -1573,6 +1588,11 @@ pre code {
opacity: 1;
}
+.form-control::-moz-placeholder {
+ color: #868e96;
+ opacity: 1;
+}
+
.form-control:-ms-input-placeholder {
color: #868e96;
opacity: 1;
@@ -1956,7 +1976,7 @@ select.form-control-lg:not([size]):not([multiple]), .input-group-lg > select.for
font-size: 1rem;
line-height: 1.25;
border-radius: 0.25rem;
- transition: all 0.2s ease-in-out;
+ transition: all 0.15s ease-in-out;
}
.btn:focus, .btn:hover {
@@ -3825,8 +3845,10 @@ tbody.collapse.show {
@media (min-width: 576px) {
.card-columns {
-webkit-column-count: 3;
+ -moz-column-count: 3;
column-count: 3;
-webkit-column-gap: 1.25rem;
+ -moz-column-gap: 1.25rem;
column-gap: 1.25rem;
}
.card-columns .card {
@@ -4553,49 +4575,6 @@ button.list-group-item-dark.active {
border-color: #1b1e21;
}
-.embed-responsive {
- position: relative;
- display: block;
- width: 100%;
- padding: 0;
- overflow: hidden;
-}
-
-.embed-responsive::before {
- display: block;
- content: "";
-}
-
-.embed-responsive .embed-responsive-item,
-.embed-responsive iframe,
-.embed-responsive embed,
-.embed-responsive object,
-.embed-responsive video {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- width: 100%;
- height: 100%;
- border: 0;
-}
-
-.embed-responsive-21by9::before {
- padding-top: 42.857143%;
-}
-
-.embed-responsive-16by9::before {
- padding-top: 56.25%;
-}
-
-.embed-responsive-4by3::before {
- padding-top: 75%;
-}
-
-.embed-responsive-1by1::before {
- padding-top: 100%;
-}
-
.close {
float: right;
font-size: 1.5rem;
@@ -5616,6 +5595,49 @@ a.bg-dark:focus, a.bg-dark:hover {
}
}
+.embed-responsive {
+ position: relative;
+ display: block;
+ width: 100%;
+ padding: 0;
+ overflow: hidden;
+}
+
+.embed-responsive::before {
+ display: block;
+ content: "";
+}
+
+.embed-responsive .embed-responsive-item,
+.embed-responsive iframe,
+.embed-responsive embed,
+.embed-responsive object,
+.embed-responsive video {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ border: 0;
+}
+
+.embed-responsive-21by9::before {
+ padding-top: 42.857143%;
+}
+
+.embed-responsive-16by9::before {
+ padding-top: 56.25%;
+}
+
+.embed-responsive-4by3::before {
+ padding-top: 75%;
+}
+
+.embed-responsive-1by1::before {
+ padding-top: 100%;
+}
+
.flex-row {
-ms-flex-direction: row !important;
flex-direction: row !important;
diff --git a/library/bootstrap/css/bootstrap.css.map b/library/bootstrap/css/bootstrap.css.map
index 97f1c07dc..183a9b0c0 100644
--- a/library/bootstrap/css/bootstrap.css.map
+++ b/library/bootstrap/css/bootstrap.css.map
@@ -1 +1 @@
-{"version":3,"sources":["../../scss/bootstrap.scss","../../scss/_print.scss","bootstrap.css","../../scss/_reboot.scss","../../scss/_variables.scss","../../scss/mixins/_hover.scss","../../scss/_type.scss","../../scss/mixins/_lists.scss","../../scss/_images.scss","../../scss/mixins/_image.scss","../../scss/mixins/_border-radius.scss","../../scss/mixins/_transition.scss","../../scss/_code.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/mixins/_breakpoints.scss","../../scss/mixins/_grid-framework.scss","../../scss/_tables.scss","../../scss/mixins/_table-row.scss","../../scss/_functions.scss","../../scss/_forms.scss","../../scss/mixins/_forms.scss","../../scss/_buttons.scss","../../scss/mixins/_buttons.scss","../../scss/_transitions.scss","../../scss/_dropdown.scss","../../scss/mixins/_nav-divider.scss","../../scss/_button-group.scss","../../scss/_input-group.scss","../../scss/_custom-forms.scss","../../scss/_nav.scss","../../scss/_navbar.scss","../../scss/_card.scss","../../scss/_breadcrumb.scss","../../scss/mixins/_clearfix.scss","../../scss/_pagination.scss","../../scss/mixins/_pagination.scss","../../scss/_badge.scss","../../scss/mixins/_badge.scss","../../scss/_jumbotron.scss","../../scss/_alert.scss","../../scss/mixins/_alert.scss","../../scss/_progress.scss","../../scss/mixins/_gradients.scss","../../scss/_media.scss","../../scss/_list-group.scss","../../scss/mixins/_list-group.scss","../../scss/_responsive-embed.scss","../../scss/_close.scss","../../scss/_modal.scss","../../scss/_tooltip.scss","../../scss/mixins/_reset-text.scss","../../scss/_popover.scss","../../scss/_carousel.scss","../../scss/utilities/_align.scss","../../scss/mixins/_background-variant.scss","../../scss/utilities/_background.scss","../../scss/utilities/_borders.scss","../../scss/utilities/_display.scss","../../scss/utilities/_flex.scss","../../scss/utilities/_float.scss","../../scss/mixins/_float.scss","../../scss/utilities/_position.scss","../../scss/utilities/_screenreaders.scss","../../scss/mixins/_screen-reader.scss","../../scss/utilities/_sizing.scss","../../scss/utilities/_spacing.scss","../../scss/utilities/_text.scss","../../scss/mixins/_text-truncate.scss","../../scss/mixins/_text-emphasis.scss","../../scss/mixins/_text-hide.scss","../../scss/utilities/_visibility.scss","../../scss/mixins/_visibility.scss"],"names":[],"mappings":"AAAA;;;;;GAKG;ACMD;EACE;;;;;;;;;;;IAcE,6BAA4B;IAE5B,4BAA2B;GAC5B;EAED;;IAEE,2BAA0B;GAC3B;EAOD;IACE,8BAA6B;GAC9B;EAaD;IACE,iCAAgC;GACjC;EACD;;IAEE,uBAAgC;IAChC,yBAAwB;GACzB;EAOD;IACE,4BAA2B;GAC5B;EAED;;IAEE,yBAAwB;GACzB;EAED;;;IAGE,WAAU;IACV,UAAS;GACV;EAED;;IAEE,wBAAuB;GACxB;EAKD;IACE,cAAa;GACd;EACD;IACE,uBAAgC;GACjC;EAED;IACE,qCAAoC;GAMrC;EAPD;;IAKI,kCAAiC;GAClC;EAEH;;IAGI,kCAAiC;GAClC;CC3CN;;AClDD;EACE,uBAAsB;EACtB,wBAAuB;EACvB,kBAAiB;EACjB,+BAA8B;EAC9B,2BAA0B;EAC1B,8BAA6B;EAC7B,yCAA0C;CAC3C;;AAED;;;EAGE,oBAAmB;CACpB;;AAIC;EAAgB,oBAAmB;CDoDpC;;AChDD;EACE,eAAc;CACf;;AAOD;EACE,UAAS;EACT,wGCoLiH;EDnLjH,gBCuLmB;EDtLnB,oBC2LyB;ED1LzB,iBC8LoB;ED7LpB,eCEgB;EDDhB,uBCRW;CDSZ;;AD+CD;ECvCE,yBAAwB;CACzB;;AAQD;EACE,wBAAuB;EACvB,UAAS;EACT,kBAAiB;CAClB;;AAWD;EACE,cAAa;EACb,qBAAoB;CACrB;;AAMD;EACE,cAAa;EACb,oBAAmB;CACpB;;AASD;;EAEE,2BAA0B;EAC1B,kCAAiC;EACjC,aAAY;EACZ,iBAAgB;CACjB;;AAED;EACE,oBAAmB;EACnB,mBAAkB;EAClB,qBAAoB;CACrB;;AAED;;;EAGE,cAAa;EACb,oBAAmB;CACpB;;AAED;;;;EAIE,iBAAgB;CACjB;;AAED;EACE,kBCsGqB;CDrGtB;;AAED;EACE,qBAAoB;EACpB,eAAc;CACf;;AAED;EACE,iBAAgB;CACjB;;AAED;EACE,mBAAkB;CACnB;;AAED;;EAEE,oBAAmB;CACpB;;AAED;EACE,eAAc;CACf;;AAOD;;EAEE,mBAAkB;EAClB,eAAc;EACd,eAAc;EACd,yBAAwB;CACzB;;AAED;EAAM,eAAc;CAAK;;AACzB;EAAM,WAAU;CAAK;;AAOrB;EACE,eClHe;EDmHf,sBCxB0B;EDyB1B,8BAA6B;EAC7B,sCAAqC;CAMtC;;AE1LG;EFuLA,eC5B4C;ED6B5C,2BC5B6B;CC5JR;;AFkMzB;EACE,eAAc;EACd,sBAAqB;CAUtB;;AEnMG;EF4LA,eAAc;EACd,sBAAqB;CE1LpB;;AFoLL;EAUI,WAAU;CACX;;AAQH;;;;EAIE,kCAAiC;EACjC,eAAc;CACf;;AAED;EAEE,cAAa;EAEb,oBAAmB;EAEnB,eAAc;CACf;;AAOD;EAEE,iBAAgB;CACjB;;AAOD;EACE,uBAAsB;EACtB,mBAAkB;CACnB;;AAED;EACE,iBAAgB;CACjB;;AAaD;;;;;;;;;EASE,+BAA0B;MAA1B,2BAA0B;CAC3B;;AAOD;EACE,0BAAyB;CAC1B;;AAED;EACE,qBCGoC;EDFpC,wBCEoC;EDDpC,eCpPgB;EDqPhB,iBAAgB;EAChB,qBAAoB;CACrB;;AAED;EAEE,iBAAgB;CACjB;;AAOD;EAEE,sBAAqB;EACrB,qBAAoB;CACrB;;AAMD;EACE,oBAAmB;EACnB,2CAA0C;CAC3C;;AAED;;;;;EAKE,UAAS;EACT,qBAAoB;EACpB,mBAAkB;EAClB,qBAAoB;CACrB;;AAED;;EAEE,kBAAiB;CAClB;;AAED;;EAEE,qBAAoB;CACrB;;AAKD;;;;EAIE,2BAA0B;CAC3B;;AAGD;;;;EAIE,WAAU;EACV,mBAAkB;CACnB;;AAED;;EAEE,uBAAsB;EACtB,WAAU;CACX;;AAGD;;;;EASE,4BAA2B;CAC5B;;AAED;EACE,eAAc;EAEd,iBAAgB;CACjB;;AAED;EAME,aAAY;EAEZ,WAAU;EACV,UAAS;EACT,UAAS;CACV;;AAID;EACE,eAAc;EACd,YAAW;EACX,gBAAe;EACf,WAAU;EACV,qBAAoB;EACpB,kBAAiB;EACjB,qBAAoB;EACpB,eAAc;EACd,oBAAmB;CACpB;;AAED;EACE,yBAAwB;CACzB;;AD5DD;;ECiEE,aAAY;CACb;;AD7DD;ECoEE,qBAAoB;EACpB,yBAAwB;CACzB;;ADjED;;ECyEE,yBAAwB;CACzB;;AAOD;EACE,cAAa;EACb,2BAA0B;CAC3B;;AAMD;EACE,sBAAqB;CACtB;;AAED;EACE,mBAAkB;CACnB;;AAED;EACE,cAAa;CACd;;AD9ED;ECmFE,yBAAwB;CACzB;;AG5dD;;EAEE,sBFyPoC;EExPpC,qBFyP8B;EExP9B,iBFyP0B;EExP1B,iBFyP0B;EExP1B,eFyP8B;CExP/B;;AAED;EAAU,kBF2OW;CE3OiB;;AACtC;EAAU,gBF2OS;CE3OmB;;AACtC;EAAU,mBF2OY;CE3OgB;;AACtC;EAAU,kBF2OW;CE3OiB;;AACtC;EAAU,mBF2OY;CE3OgB;;AACtC;EAAU,gBF2OS;CE3OmB;;AAEtC;EACE,mBF2PwB;EE1PxB,iBF2PoB;CE1PrB;;AAGD;EACE,gBF0OkB;EEzOlB,iBF8OuB;EE7OvB,iBFqO0B;CEpO3B;;AACD;EACE,kBFsOoB;EErOpB,iBF0OuB;EEzOvB,iBFgO0B;CE/N3B;;AACD;EACE,kBFkOoB;EEjOpB,iBFsOuB;EErOvB,iBF2N0B;CE1N3B;;AACD;EACE,kBF8NoB;EE7NpB,iBFkOuB;EEjOvB,iBFsN0B;CErN3B;;AAOD;EACE,iBAAgB;EAChB,oBAAmB;EACnB,UAAS;EACT,yCFIW;CEHZ;;AAOD;;EAEE,eFiNmB;EEhNnB,oBF+KyB;CE9K1B;;AAED;;EAEE,eFqNiB;EEpNjB,0BF6Ne;CE5NhB;;AAOD;EC7EE,gBAAe;EACf,iBAAgB;CD8EjB;;AAGD;EClFE,gBAAe;EACf,iBAAgB;CDmFjB;;AACD;EACE,sBAAqB;CAKtB;;AAND;EAII,kBFuMqB;CEtMtB;;AASH;EACE,eAAc;EACd,0BAAyB;CAC1B;;AAGD;EACE,oBFyBW;EExBX,mBFyKgD;CExKjD;;AAED;EACE,eAAc;EACd,eAAc;EACd,eF7DgB;CEkEjB;;AARD;EAMI,uBAAsB;CACvB;;AElHH;ECIE,gBAAe;EAGf,aAAY;CDLb;;AAID;EACE,iBJuxBkC;EItxBlC,uBJmCW;EIlCX,uBJwxBgC;EMpyB9B,uBNmN2B;EOlNzB,iCPsyB2C;EKhyB/C,gBAAe;EAGf,aAAY;CDSb;;AAMD;EAEE,sBAAqB;CACtB;;AAED;EACE,sBAA4B;EAC5B,eAAc;CACf;;AAED;EACE,eJwwB4B;EIvwB5B,eJegB;CIdjB;;AIzCD;;;;EAIE,kFRqO2F;CQpO5F;;AAGD;EACE,uBRu1BiC;EQt1BjC,eRo1B+B;EQn1B/B,eRs1BmC;EQr1BnC,0BRsCgB;EM/Cd,uBNmN2B;CQjM9B;;AALC;EACE,WAAU;EACV,eAAc;EACd,0BAAyB;CAC1B;;AAIH;EACE,uBRu0BiC;EQt0BjC,eRo0B+B;EQn0B/B,YRsBW;EQrBX,0BR8BgB;EMvDd,sBNqN0B;CQlL7B;;AAdD;EASI,WAAU;EACV,gBAAe;EACf,kBR+MmB;CQ7MpB;;AAIH;EACE,eAAc;EACd,cAAa;EACb,oBAAmB;EACnB,eRizB+B;EQhzB/B,eRYgB;CQFjB;;AAfD;EASI,WAAU;EACV,mBAAkB;EAClB,eAAc;EACd,8BAA6B;EAC7B,iBAAgB;CACjB;;AAIH;EACE,kBR4yBiC;EQ3yBjC,mBAAkB;CACnB;;AC1DC;ECAA,mBAAkB;EAClB,kBAAiB;EACjB,oBAAuC;EACvC,mBAAuC;CDAtC;;AEgDC;EFnDF;ICWI,aV+KK;IU9KL,gBAAe;GDTlB;CXgmBF;;AahjBG;EFnDF;ICWI,aVgLK;IU/KL,gBAAe;GDTlB;CXumBF;;AavjBG;EFnDF;ICWI,aViLK;IUhLL,gBAAe;GDTlB;CX8mBF;;Aa9jBG;EFnDF;ICWI,cVkLM;IUjLN,gBAAe;GDTlB;CXqnBF;;AW5mBC;EACE,YAAW;ECbb,mBAAkB;EAClB,kBAAiB;EACjB,oBAAuC;EACvC,mBAAuC;CDYtC;;AAQD;ECLA,qBAAa;EAAb,cAAa;EACb,oBAAe;MAAf,gBAAe;EACf,oBAAuC;EACvC,mBAAuC;CDItC;;AAID;EACE,gBAAe;EACf,eAAc;CAOf;;AATD;;EAMI,iBAAgB;EAChB,gBAAe;CAChB;;AGnCH;;;;;;EACE,mBAAkB;EAClB,YAAW;EACX,gBAAe;EACf,oBAA4B;EAC5B,mBAA4B;CAC7B;;AAkBG;EACE,2BAAa;MAAb,cAAa;EACb,qBAAY;MAAZ,aAAY;EACZ,gBAAe;CAChB;;AACD;EACE,mBAAc;MAAd,eAAc;EACd,YAAW;EACX,gBAAe;CAChB;;AAGC;EFFN,wBAAsC;MAAtC,oBAAsC;EAItC,qBAAuC;CEAhC;;AAFD;EFFN,yBAAsC;MAAtC,qBAAsC;EAItC,sBAAuC;CEAhC;;AAFD;EFFN,kBAAsC;MAAtC,cAAsC;EAItC,eAAuC;CEAhC;;AAFD;EFFN,yBAAsC;MAAtC,qBAAsC;EAItC,sBAAuC;CEAhC;;AAFD;EFFN,yBAAsC;MAAtC,qBAAsC;EAItC,sBAAuC;CEAhC;;AAFD;EFFN,kBAAsC;MAAtC,cAAsC;EAItC,eAAuC;CEAhC;;AAFD;EFFN,yBAAsC;MAAtC,qBAAsC;EAItC,sBAAuC;CEAhC;;AAFD;EFFN,yBAAsC;MAAtC,qBAAsC;EAItC,sBAAuC;CEAhC;;AAFD;EFFN,kBAAsC;MAAtC,cAAsC;EAItC,eAAuC;CEAhC;;AAFD;EFFN,yBAAsC;MAAtC,qBAAsC;EAItC,sBAAuC;CEAhC;;AAFD;EFFN,yBAAsC;MAAtC,qBAAsC;EAItC,sBAAuC;CEAhC;;AAFD;EFFN,mBAAsC;MAAtC,eAAsC;EAItC,gBAAuC;CEAhC;;AAID;EACE,kBAFU;MAEV,SAFU;CAGX;;AAFD;EACE,kBAFU;MAEV,SAFU;CAGX;;AAFD;EACE,kBAFU;MAEV,SAFU;CAGX;;AAFD;EACE,kBAFU;MAEV,SAFU;CAGX;;AAFD;EACE,kBAFU;MAEV,SAFU;CAGX;;AAFD;EACE,kBAFU;MAEV,SAFU;CAGX;;AAFD;EACE,kBAFU;MAEV,SAFU;CAGX;;AAFD;EACE,kBAFU;MAEV,SAFU;CAGX;;AAFD;EACE,kBAFU;MAEV,SAFU;CAGX;;AAFD;EACE,mBAFU;MAEV,UAFU;CAGX;;AAFD;EACE,mBAFU;MAEV,UAFU;CAGX;;AAFD;EACE,mBAFU;MAEV,UAFU;CAGX;;ADKL;ECzBE;IACE,2BAAa;QAAb,cAAa;IACb,qBAAY;QAAZ,aAAY;IACZ,gBAAe;GAChB;EACD;IACE,mBAAc;QAAd,eAAc;IACd,YAAW;IACX,gBAAe;GAChB;EAGC;IFFN,wBAAsC;QAAtC,oBAAsC;IAItC,qBAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,kBAAsC;QAAtC,cAAsC;IAItC,eAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,kBAAsC;QAAtC,cAAsC;IAItC,eAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,kBAAsC;QAAtC,cAAsC;IAItC,eAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,mBAAsC;QAAtC,eAAsC;IAItC,gBAAuC;GEAhC;EAID;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,mBAFU;QAEV,UAFU;GAGX;EAFD;IACE,mBAFU;QAEV,UAFU;GAGX;EAFD;IACE,mBAFU;QAEV,UAFU;GAGX;Cd00BR;;Aar0BG;ECzBE;IACE,2BAAa;QAAb,cAAa;IACb,qBAAY;QAAZ,aAAY;IACZ,gBAAe;GAChB;EACD;IACE,mBAAc;QAAd,eAAc;IACd,YAAW;IACX,gBAAe;GAChB;EAGC;IFFN,wBAAsC;QAAtC,oBAAsC;IAItC,qBAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,kBAAsC;QAAtC,cAAsC;IAItC,eAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,kBAAsC;QAAtC,cAAsC;IAItC,eAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,kBAAsC;QAAtC,cAAsC;IAItC,eAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,mBAAsC;QAAtC,eAAsC;IAItC,gBAAuC;GEAhC;EAID;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,mBAFU;QAEV,UAFU;GAGX;EAFD;IACE,mBAFU;QAEV,UAFU;GAGX;EAFD;IACE,mBAFU;QAEV,UAFU;GAGX;Cd26BR;;Aat6BG;ECzBE;IACE,2BAAa;QAAb,cAAa;IACb,qBAAY;QAAZ,aAAY;IACZ,gBAAe;GAChB;EACD;IACE,mBAAc;QAAd,eAAc;IACd,YAAW;IACX,gBAAe;GAChB;EAGC;IFFN,wBAAsC;QAAtC,oBAAsC;IAItC,qBAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,kBAAsC;QAAtC,cAAsC;IAItC,eAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,kBAAsC;QAAtC,cAAsC;IAItC,eAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,kBAAsC;QAAtC,cAAsC;IAItC,eAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,mBAAsC;QAAtC,eAAsC;IAItC,gBAAuC;GEAhC;EAID;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,mBAFU;QAEV,UAFU;GAGX;EAFD;IACE,mBAFU;QAEV,UAFU;GAGX;EAFD;IACE,mBAFU;QAEV,UAFU;GAGX;Cd4gCR;;AavgCG;ECzBE;IACE,2BAAa;QAAb,cAAa;IACb,qBAAY;QAAZ,aAAY;IACZ,gBAAe;GAChB;EACD;IACE,mBAAc;QAAd,eAAc;IACd,YAAW;IACX,gBAAe;GAChB;EAGC;IFFN,wBAAsC;QAAtC,oBAAsC;IAItC,qBAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,kBAAsC;QAAtC,cAAsC;IAItC,eAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,kBAAsC;QAAtC,cAAsC;IAItC,eAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,kBAAsC;QAAtC,cAAsC;IAItC,eAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,yBAAsC;QAAtC,qBAAsC;IAItC,sBAAuC;GEAhC;EAFD;IFFN,mBAAsC;QAAtC,eAAsC;IAItC,gBAAuC;GEAhC;EAID;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,kBAFU;QAEV,SAFU;GAGX;EAFD;IACE,mBAFU;QAEV,UAFU;GAGX;EAFD;IACE,mBAFU;QAEV,UAFU;GAGX;EAFD;IACE,mBAFU;QAEV,UAFU;GAGX;Cd6mCR;;Ae5pCD;EACE,YAAW;EACX,gBAAe;EACf,oBbgIW;Ea/HX,8BbwSyC;CanR1C;;AAzBD;;EAQI,iBbiSkC;EahSlC,oBAAmB;EACnB,8BbsCc;CarCf;;AAXH;EAcI,uBAAsB;EACtB,iCbiCc;CahCf;;AAhBH;EAmBI,8Bb6Bc;Ca5Bf;;AApBH;EAuBI,uBbuBS;CatBV;;AAQH;;EAGI,gBbuQiC;CatQlC;;AAQH;EACE,0BbGgB;CaUjB;;AAdD;;EAKI,0BbDc;CaEf;;AANH;;EAWM,yBAA8C;CAC/C;;AASL;EAEI,sCbXS;CaYV;;AAQH;EAGM,uCbvBO;CCjDY;;AaNvB;;;EAII,0BC4EmE;CD3EpE;;AAKH;EAKM,0BAJsC;CbLrB;;AaIvB;;EASQ,0BARoC;CASrC;;AApBP;;;EAII,0BC4EmE;CD3EpE;;AAKH;EAKM,0BAJsC;CbLrB;;AaIvB;;EASQ,0BARoC;CASrC;;AApBP;;;EAII,0BC4EmE;CD3EpE;;AAKH;EAKM,0BAJsC;CbLrB;;AaIvB;;EASQ,0BARoC;CASrC;;AApBP;;;EAII,0BC4EmE;CD3EpE;;AAKH;EAKM,0BAJsC;CbLrB;;AaIvB;;EASQ,0BARoC;CASrC;;AApBP;;;EAII,0BC4EmE;CD3EpE;;AAKH;EAKM,0BAJsC;CbLrB;;AaIvB;;EASQ,0BARoC;CASrC;;AApBP;;;EAII,0BC4EmE;CD3EpE;;AAKH;EAKM,0BAJsC;CbLrB;;AaIvB;;EASQ,0BARoC;CASrC;;AApBP;;;EAII,0BC4EmE;CD3EpE;;AAKH;EAKM,0BAJsC;CbLrB;;AaIvB;;EASQ,0BARoC;CASrC;;AApBP;;;EAII,0BC4EmE;CD3EpE;;AAKH;EAKM,0BAJsC;CbLrB;;AaIvB;;EASQ,0BARoC;CASrC;;AD8ET;EAEI,YbvDS;EawDT,0Bb/Cc;CagDf;;AAGH;EAEI,ebvDc;EawDd,0Bb7Dc;Ca8Df;;AAGH;EACE,YbpEW;EaqEX,0Bb5DgB;CaqFjB;;AA3BD;;;EAOI,sBbkMoD;CajMrD;;AARH;EAWI,UAAS;CACV;;AAZH;EAgBM,4CbnFO;CaoFR;;AAjBL;EAuBQ,6Cb1FK;CCvCY;;AU0DrB;EEoFJ;IAEI,eAAc;IACd,YAAW;IACX,iBAAgB;IAChB,6CAA4C;GAO/C;EAZD;IASM,UAAS;GACV;CfwtCJ;;AkBr3CD;EACE,eAAc;EACd,YAAW;EAGX,wBhB4TgC;EgB3ThC,gBhBiOmB;EgBhOnB,kBhB2T8B;EgB1T9B,ehB2CgB;EgB1ChB,uBhBmCW;EgBjCX,uBAAsB;EACtB,6BAA4B;EAC5B,sChByCW;EgBpCT,uBhB+L2B;EOlNzB,yEPsZqF;CgB/V1F;;AAtDD;EA6BI,8BAA6B;EAC7B,UAAS;CACV;;ACxBD;EACE,ejB2Cc;EiB1Cd,uBjBmCS;EiBlCT,sBjB0XiE;EiBzXjE,cAAa;CAEd;;ADbH;EAsCI,ehBYc;EgBVd,WAAU;CACX;;AAzCH;EAsCI,ehBYc;EgBVd,WAAU;CACX;;AAzCH;EAsCI,ehBYc;EgBVd,WAAU;CACX;;AAzCH;EAkDI,0BhBJc;EgBMd,WAAU;CACX;;AAGH;EAEI,4BhBmVkF;CgBlVnF;;AAHH;EAWI,ehBhBc;EgBiBd,uBhBxBS;CgByBV;;AAIH;;EAEE,eAAc;CACf;;AASD;EACE,oCAA2E;EAC3E,uCAA8E;EAC9E,iBAAgB;CACjB;;AAED;EACE,oCAA8E;EAC9E,uCAAiF;EACjF,mBhB0IsB;CgBzIvB;;AAED;EACE,qCAA8E;EAC9E,wCAAiF;EACjF,oBhBqIsB;CgBpIvB;;AASD;EACE,oBhBiN+B;EgBhN/B,uBhBgN+B;EgB/M/B,iBAAgB;EAChB,gBhBqHmB;CgBpHpB;;AAQD;EACE,oBhBoM+B;EgBnM/B,uBhBmM+B;EgBlM/B,iBAAgB;EAChB,kBhBmM8B;EgBlM9B,0BAAyB;EACzB,oBAAuC;CAOxC;;AAbD;;;;;EAUI,iBAAgB;EAChB,gBAAe;CAChB;;AAYH;;;EACE,wBhBiL+B;EgBhL/B,oBhBoFsB;EgBnFtB,iBhBgL6B;EMxU3B,sBNqN0B;CgB3D7B;;AAED;;;EAEI,8BhBoPqF;CgBnPtF;;AAGH;;;EACE,qBhBwK8B;EgBvK9B,mBhBsEsB;EgBrEtB,iBhBuK6B;EM5U3B,sBNoN0B;CgB7C7B;;AAED;;;EAEI,8BhB0OqF;CgBzOtF;;AASH;EACE,oBhB6OmC;CgB5OpC;;AAED;EACE,eAAc;EACd,oBhB8N+B;CgB7NhC;;AAOD;EACE,qBAAa;EAAb,cAAa;EACb,oBAAe;MAAf,gBAAe;EACf,mBAAkB;EAClB,kBAAiB;CAOlB;;AAXD;;EAQI,mBAAkB;EAClB,kBAAiB;CAClB;;AAQH;EACE,mBAAkB;EAClB,eAAc;EACd,sBhBoM+B;CgB7LhC;;AAVD;EAOM,ehBxKY;CgByKb;;AAIL;EACE,sBhB2LiC;EgB1LjC,iBAAgB;CACjB;;AAED;EACE,mBAAkB;EAClB,oBhBsLgC;EgBrLhC,sBhBoLiC;CgB/KlC;;AARD;EAMI,iBAAgB;CACjB;;AAIH;EACE,sBAAqB;CAStB;;AAVD;EAII,uBAAsB;CACvB;;AALH;EAQI,qBhBwK+B;CgBvKhC;;AAWH;EACE,cAAa;EACb,mBAAkB;EAClB,mBAAkB;EAClB,ehB/Le;CgBgMhB;;AAED;EACE,mBAAkB;EAClB,UAAS;EACT,WAAU;EACV,cAAa;EACb,aAAY;EACZ,eAAc;EACd,kBAAiB;EACjB,mBAAkB;EAClB,eAAc;EACd,YAAW;EACX,yChB7Me;EgB8Mf,qBAAoB;CACrB;;AClQG;;;EAEE,sBjBoDW;CiB1CZ;;AAZD;;;EAKI,iDjBiDS;CiBhDV;;AANH;;;;;;;;EAUI,eAAc;CACf;;AAOH;EAGI,ejBiCS;CiBhCV;;AAMH;EAGI,0CjBuBS;CiBtBV;;AAJH;EAMI,ejBoBS;CiBnBV;;AAMH;EAGI,sBjBUS;CiBPV;;AANH;EAKgB,sBAAqB;CAAK;;AAL1C;EAQI,iDjBKS;CiBJV;;AAlDH;;;EAEE,sBjBiDW;CiBvCZ;;AAZD;;;EAKI,iDjB8CS;CiB7CV;;AANH;;;;;;;;EAUI,eAAc;CACf;;AAOH;EAGI,ejB8BS;CiB7BV;;AAMH;EAGI,0CjBoBS;CiBnBV;;AAJH;EAMI,ejBiBS;CiBhBV;;AAMH;EAGI,sBjBOS;CiBJV;;AANH;EAKgB,sBAAqB;CAAK;;AAL1C;EAQI,iDjBES;CiBDV;;AD8NP;EACE,qBAAa;EAAb,cAAa;EACb,wBAAmB;MAAnB,oBAAmB;EACnB,uBAAmB;MAAnB,oBAAmB;CAuFpB;;AA1FD;EASI,YAAW;CACZ;;AL7PC;EKmPJ;IAeM,qBAAa;IAAb,cAAa;IACb,uBAAmB;QAAnB,oBAAmB;IACnB,sBAAuB;QAAvB,wBAAuB;IACvB,iBAAgB;GACjB;EAnBL;IAuBM,qBAAa;IAAb,cAAa;IACb,mBAAc;QAAd,eAAc;IACd,wBAAmB;QAAnB,oBAAmB;IACnB,uBAAmB;QAAnB,oBAAmB;IACnB,iBAAgB;GACjB;EA5BL;IAgCM,sBAAqB;IACrB,YAAW;IACX,uBAAsB;GACvB;EAnCL;IAuCM,sBAAqB;GACtB;EAxCL;IA2CM,YAAW;GACZ;EA5CL;IA+CM,iBAAgB;IAChB,uBAAsB;GACvB;EAjDL;IAsDM,qBAAa;IAAb,cAAa;IACb,uBAAmB;QAAnB,oBAAmB;IACnB,sBAAuB;QAAvB,wBAAuB;IACvB,YAAW;IACX,cAAa;IACb,iBAAgB;GACjB;EA5DL;IA8DM,gBAAe;GAChB;EA/DL;IAiEM,mBAAkB;IAClB,cAAa;IACb,sBhBqD4B;IgBpD5B,eAAc;GACf;EArEL;IAyEM,qBAAa;IAAb,cAAa;IACb,uBAAmB;QAAnB,oBAAmB;IACnB,sBAAuB;QAAvB,wBAAuB;IACvB,gBAAe;GAChB;EA7EL;IA+EM,iBAAgB;IAChB,sBAAqB;IACrB,sBhBuC4B;IgBtC5B,4BAA2B;GAC5B;EAnFL;IAuFM,OAAM;GACP;ClB42CJ;;AoBzuDD;EACE,sBAAqB;EACrB,oBlB0OyB;EkBzOzB,mBAAkB;EAClB,oBAAmB;EACnB,uBAAsB;EACtB,0BAAiB;KAAjB,uBAAiB;MAAjB,sBAAiB;UAAjB,kBAAiB;EACjB,8BAAiD;ECqEjD,wBnBqPgC;EmBpPhC,gBnB0JmB;EmBzJnB,kBnBoP8B;EMpU5B,uBNmN2B;EOlNzB,iCPmX8C;CkBjVnD;;AjBjBG;EiBHA,sBAAqB;CjBMpB;;AiBnBL;EAiBI,WAAU;EACV,8ClBkDa;CkBjDd;;AAnBH;EAwBI,aAAY;CAEb;;AA1BH;EA8BI,uBAAsB;CAEvB;;AAIH;;EAEE,qBAAoB;CACrB;;AAQC;EHQE,YAAW;EInDb,0BnBgEe;EmB/Df,sBnB+De;CkBnBd;;ACxCD;EJ8CE,YAAW;EI5CX,0BAX2C;EAY3C,sBAXkC;CAYnC;;AAED;EAMI,6CnB+CW;CmB7Cd;;AAGD;EAEE,0BnBwCa;EmBvCb,sBnBuCa;CmBtCd;;AAED;;EAGE,0BAnC2C;EAoC3C,uBAAsB;EACtB,sBApCkC;CAsCnC;;ADQD;EHQE,YAAW;EInDb,0BnB8CgB;EmB7ChB,sBnB6CgB;CkBDf;;ACxCD;EJ8CE,YAAW;EI5CX,0BAX2C;EAY3C,sBAXkC;CAYnC;;AAED;EAMI,+CnB6BY;CmB3Bf;;AAGD;EAEE,0BnBsBc;EmBrBd,sBnBqBc;CmBpBf;;AAED;;EAGE,0BAnC2C;EAoC3C,uBAAsB;EACtB,sBApCkC;CAsCnC;;ADQD;EHQE,YAAW;EInDb,0BnBuEe;EmBtEf,sBnBsEe;CkB1Bd;;ACxCD;EJ8CE,YAAW;EI5CX,0BAX2C;EAY3C,sBAXkC;CAYnC;;AAED;EAMI,6CnBsDW;CmBpDd;;AAGD;EAEE,0BnB+Ca;EmB9Cb,sBnB8Ca;CmB7Cd;;AAED;;EAGE,0BAnC2C;EAoC3C,uBAAsB;EACtB,sBApCkC;CAsCnC;;ADQD;EHQE,YAAW;EInDb,0BnByEe;EmBxEf,sBnBwEe;CkB5Bd;;ACxCD;EJ8CE,YAAW;EI5CX,0BAX2C;EAY3C,sBAXkC;CAYnC;;AAED;EAMI,8CnBwDW;CmBtDd;;AAGD;EAEE,0BnBiDa;EmBhDb,sBnBgDa;CmB/Cd;;AAED;;EAGE,0BAnC2C;EAoC3C,uBAAsB;EACtB,sBApCkC;CAsCnC;;ADQD;EHME,YAAW;EIjDb,0BnBsEe;EmBrEf,sBnBqEe;CkBzBd;;ACxCD;EJ4CE,YAAW;EI1CX,0BAX2C;EAY3C,sBAXkC;CAYnC;;AAED;EAMI,6CnBqDW;CmBnDd;;AAGD;EAEE,0BnB8Ca;EmB7Cb,sBnB6Ca;CmB5Cd;;AAED;;EAGE,0BAnC2C;EAoC3C,uBAAsB;EACtB,sBApCkC;CAsCnC;;ADQD;EHQE,YAAW;EInDb,0BnBoEe;EmBnEf,sBnBmEe;CkBvBd;;ACxCD;EJ8CE,YAAW;EI5CX,0BAX2C;EAY3C,sBAXkC;CAYnC;;AAED;EAMI,6CnBmDW;CmBjDd;;AAGD;EAEE,0BnB4Ca;EmB3Cb,sBnB2Ca;CmB1Cd;;AAED;;EAGE,0BAnC2C;EAoC3C,uBAAsB;EACtB,sBApCkC;CAsCnC;;ADQD;EHME,YAAW;EIjDb,0BnByCgB;EmBxChB,sBnBwCgB;CkBIf;;ACxCD;EJ4CE,YAAW;EI1CX,0BAX2C;EAY3C,sBAXkC;CAYnC;;AAED;EAMI,+CnBwBY;CmBtBf;;AAGD;EAEE,0BnBiBc;EmBhBd,sBnBgBc;CmBff;;AAED;;EAGE,0BAnC2C;EAoC3C,uBAAsB;EACtB,sBApCkC;CAsCnC;;ADQD;EHQE,YAAW;EInDb,0BnBgDgB;EmB/ChB,sBnB+CgB;CkBHf;;ACxCD;EJ8CE,YAAW;EI5CX,0BAX2C;EAY3C,sBAXkC;CAYnC;;AAED;EAMI,4CnB+BY;CmB7Bf;;AAGD;EAEE,0BnBwBc;EmBvBd,sBnBuBc;CmBtBf;;AAED;;EAGE,0BAnC2C;EAoC3C,uBAAsB;EACtB,sBApCkC;CAsCnC;;ADcD;ECVA,enByBe;EmBxBf,8BAA6B;EAC7B,uBAAsB;EACtB,sBnBsBe;CkBbd;;AjBlDC;EkB4CA,YDK4C;ECJ5C,0BnBkBa;EmBjBb,sBnBiBa;CC/DQ;;AkBiDvB;EAEE,6CnBYa;CmBXd;;AAED;EAEE,enBOa;EmBNb,8BAA6B;CAC9B;;AAED;;EAGE,YDd4C;ECe5C,0BnBDa;EmBEb,sBnBFa;CmBGd;;ADlBD;ECVA,enBOgB;EmBNhB,8BAA6B;EAC7B,uBAAsB;EACtB,sBnBIgB;CkBKf;;AjBlDC;EkB4CA,YDK4C;ECJ5C,0BnBAc;EmBCd,sBnBDc;CC7CO;;AkBiDvB;EAEE,+CnBNc;CmBOf;;AAED;EAEE,enBXc;EmBYd,8BAA6B;CAC9B;;AAED;;EAGE,YDd4C;ECe5C,0BnBnBc;EmBoBd,sBnBpBc;CmBqBf;;ADlBD;ECVA,enBgCe;EmB/Bf,8BAA6B;EAC7B,uBAAsB;EACtB,sBnB6Be;CkBpBd;;AjBlDC;EkB4CA,YDK4C;ECJ5C,0BnByBa;EmBxBb,sBnBwBa;CCtEQ;;AkBiDvB;EAEE,6CnBmBa;CmBlBd;;AAED;EAEE,enBca;EmBbb,8BAA6B;CAC9B;;AAED;;EAGE,YDd4C;ECe5C,0BnBMa;EmBLb,sBnBKa;CmBJd;;ADlBD;ECVA,enBkCe;EmBjCf,8BAA6B;EAC7B,uBAAsB;EACtB,sBnB+Be;CkBtBd;;AjBlDC;EkB4CA,YDK4C;ECJ5C,0BnB2Ba;EmB1Bb,sBnB0Ba;CCxEQ;;AkBiDvB;EAEE,8CnBqBa;CmBpBd;;AAED;EAEE,enBgBa;EmBfb,8BAA6B;CAC9B;;AAED;;EAGE,YDd4C;ECe5C,0BnBQa;EmBPb,sBnBOa;CmBNd;;ADlBD;ECVA,enB+Be;EmB9Bf,8BAA6B;EAC7B,uBAAsB;EACtB,sBnB4Be;CkBnBd;;AjBlDC;EkB4CA,YDK4C;ECJ5C,0BnBwBa;EmBvBb,sBnBuBa;CCrEQ;;AkBiDvB;EAEE,6CnBkBa;CmBjBd;;AAED;EAEE,enBaa;EmBZb,8BAA6B;CAC9B;;AAED;;EAGE,YDd4C;ECe5C,0BnBKa;EmBJb,sBnBIa;CmBHd;;ADlBD;ECVA,enB6Be;EmB5Bf,8BAA6B;EAC7B,uBAAsB;EACtB,sBnB0Be;CkBjBd;;AjBlDC;EkB4CA,YDK4C;ECJ5C,0BnBsBa;EmBrBb,sBnBqBa;CCnEQ;;AkBiDvB;EAEE,6CnBgBa;CmBfd;;AAED;EAEE,enBWa;EmBVb,8BAA6B;CAC9B;;AAED;;EAGE,YDd4C;ECe5C,0BnBGa;EmBFb,sBnBEa;CmBDd;;ADlBD;ECVA,enBEgB;EmBDhB,8BAA6B;EAC7B,uBAAsB;EACtB,sBnBDgB;CkBUf;;AjBlDC;EkB4CA,YDK4C;ECJ5C,0BnBLc;EmBMd,sBnBNc;CCxCO;;AkBiDvB;EAEE,+CnBXc;CmBYf;;AAED;EAEE,enBhBc;EmBiBd,8BAA6B;CAC9B;;AAED;;EAGE,YDd4C;ECe5C,0BnBxBc;EmByBd,sBnBzBc;CmB0Bf;;ADlBD;ECVA,enBSgB;EmBRhB,8BAA6B;EAC7B,uBAAsB;EACtB,sBnBMgB;CkBGf;;AjBlDC;EkB4CA,YDK4C;ECJ5C,0BnBEc;EmBDd,sBnBCc;CC/CO;;AkBiDvB;EAEE,4CnBJc;CmBKf;;AAED;EAEE,enBTc;EmBUd,8BAA6B;CAC9B;;AAED;;EAGE,YDd4C;ECe5C,0BnBjBc;EmBkBd,sBnBlBc;CmBmBf;;ADPH;EACE,oBlB2KyB;EkB1KzB,elBEe;EkBDf,iBAAgB;CA6BjB;;AAhCD;EASI,8BAA6B;CAE9B;;AAXH;EAeI,0BAAyB;CAC1B;;AjB3EC;EiB6EA,0BAAyB;CjB7EJ;;AAWrB;EiBqEA,elB2E4C;EkB1E5C,2BlB2E6B;EkB1E7B,8BAA6B;CjBpE5B;;AiB6CL;EA0BI,elBxCc;CkB6Cf;;AjB/EC;EiB6EE,sBAAqB;CjB1EtB;;AiBoFL;EC3BE,qBnB6P8B;EmB5P9B,mBnB2JsB;EmB1JtB,iBnB8H0B;EM9MxB,sBNoN0B;CkBzG7B;;AAED;EC/BE,wBnByP+B;EmBxP/B,oBnB4JsB;EmB3JtB,iBnB+H0B;EM/MxB,sBNqN0B;CkBtG7B;;AAOD;EACE,eAAc;EACd,YAAW;CACZ;;AAGD;EACE,mBlBgPoC;CkB/OrC;;AAGD;;;EAII,YAAW;CACZ;;AE1IH;EACE,WAAU;EbIN,iCP4NsC;CoB1N3C;;AAPD;EAKI,WAAU;CACX;;AAGH;EACE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BhyGD;EAEI,uB5B4a6B;C4B3a9B;;AjB3JC;EiBwJJ;IAMI,wB5BubyB;Y4BvbzB,gB5BubyB;I4BtbzB,4B5Bub+B;Y4Bvb/B,oB5Bub+B;G4BhblC;EAdD;IAUM,sBAAqB;IACrB,YAAW;GACZ;C9BmyGJ;;A+B//GD;EACE,sB7BszBkC;E6BrzBlC,oBAAmB;EACnB,iBAAgB;EAChB,0B7BgDgB;EMhDd,uBNmN2B;C6BhN9B;;ACNC;EACE,eAAc;EACd,YAAW;EACX,YAAW;CACZ;;ADIH;EACE,YAAW;CA2BZ;;AA5BD;EAKI,sBAAqB;EACrB,sB7ByyBiC;E6BxyBjC,qB7BwyBiC;E6BvyBjC,e7BuCc;E6BtCd,aAAiC;CAClC;;AAVH;EAmBI,2BAA0B;CAC3B;;AApBH;EAsBI,sBAAqB;CACtB;;AAvBH;EA0BI,e7BqBc;C6BpBf;;AEpCH;EACE,qBAAa;EAAb,cAAa;EAEb,gBAAe;EACf,iBAAgB;EzBAd,uBNmN2B;C+BjN9B;;AAED;EAGM,eAAc;EzBoBhB,gCNwL2B;EMvL3B,mCNuL2B;C+B1M1B;;AALL;EzBSI,iCNsM2B;EMrM3B,oCNqM2B;C+BrM1B;;AAVL;EAcI,WAAU;EACV,Y/B2BS;E+B1BT,0B/BkDa;E+BjDb,sB/BiDa;C+BhDd;;AAlBH;EAqBI,e/B2Bc;E+B1Bd,qBAAoB;EACpB,uB/BmBS;E+BlBT,mB/BmlBuC;C+BllBxC;;AAGH;EACE,mBAAkB;EAClB,eAAc;EACd,wB/BsjB0C;E+BrjB1C,kBAAiB;EACjB,kB/ByjBwC;E+BxjBxC,e/BgCe;E+B/Bf,uB/BOW;E+BNX,uB/B2jByC;C+BnjB1C;;A9B9BG;E8ByBA,e/BuH4C;E+BtH5C,sBAAqB;EACrB,0B/BGc;E+BFd,mB/ByjBuC;CCllBtC;;A+BtBH;EACE,wBhC6lBwC;EgC5lBxC,mBhCyOoB;EgCxOpB,iBhC4MwB;CgC3MzB;;AAIG;E1BoBF,+BNyL0B;EMxL1B,kCNwL0B;CgC3MvB;;AAGD;E1BCF,gCNuM0B;EMtM1B,mCNsM0B;CgCtMvB;;AAfL;EACE,wBhC2lBuC;EgC1lBvC,oBhC0OoB;EgCzOpB,iBhC6MwB;CgC5MzB;;AAIG;E1BoBF,+BN0L0B;EMzL1B,kCNyL0B;CgC5MvB;;AAGD;E1BCF,gCNwM0B;EMvM1B,mCNuM0B;CgCvMvB;;ACbP;EACE,sBAAqB;EACrB,sBjCmsBgC;EiClsBhC,ejC+rB+B;EiC9rB/B,kBjC0OqB;EiCzOrB,eAAc;EACd,YjCuCW;EiCtCX,mBAAkB;EAClB,oBAAmB;EACnB,yBAAwB;E3BVtB,uBNmN2B;CiClM9B;;AAhBD;EAcI,cAAa;CACd;;AAIH;EACE,mBAAkB;EAClB,UAAS;CACV;;AAMD;EACE,qBjC0qBgC;EiCzqBhC,oBjCyqBgC;EMxsB9B,qBN2sB+B;CiC1qBlC;;AAOC;ElBiBE,YAAW;EmB3Db,0BlCwEe;CiC5Bd;;AhCxBC;EcuCA,YAAW;EmBtDT,sBAAqB;EACrB,0BAAkC;CjCiBnC;;AgCmBH;ElBiBE,YAAW;EmB3Db,0BlCsDgB;CiCVf;;AhCxBC;EcuCA,YAAW;EmBtDT,sBAAqB;EACrB,0BAAkC;CjCiBnC;;AgCmBH;ElBiBE,YAAW;EmB3Db,0BlC+Ee;CiCnCd;;AhCxBC;EcuCA,YAAW;EmBtDT,sBAAqB;EACrB,0BAAkC;CjCiBnC;;AgCmBH;ElBiBE,YAAW;EmB3Db,0BlCiFe;CiCrCd;;AhCxBC;EcuCA,YAAW;EmBtDT,sBAAqB;EACrB,0BAAkC;CjCiBnC;;AgCmBH;ElBeE,YAAW;EmBzDb,0BlC8Ee;CiClCd;;AhCxBC;EcqCA,YAAW;EmBpDT,sBAAqB;EACrB,0BAAkC;CjCiBnC;;AgCmBH;ElBiBE,YAAW;EmB3Db,0BlC4Ee;CiChCd;;AhCxBC;EcuCA,YAAW;EmBtDT,sBAAqB;EACrB,0BAAkC;CjCiBnC;;AgCmBH;ElBeE,YAAW;EmBzDb,0BlCiDgB;CiCLf;;AhCxBC;EcqCA,YAAW;EmBpDT,sBAAqB;EACrB,0BAAkC;CjCiBnC;;AgCmBH;ElBiBE,YAAW;EmB3Db,0BlCwDgB;CiCZf;;AhCxBC;EcuCA,YAAW;EmBtDT,sBAAqB;EACrB,0BAAkC;CjCiBnC;;AkCzBL;EACE,mBAAoD;EACpD,oBnCsnBmC;EmCrnBnC,0BnCiDgB;EMhDd,sBNoN0B;CmC/M7B;;AxB+CG;EwBxDJ;IAOI,mBnCinBiC;GmC/mBpC;CrC+uHA;;AqC7uHD;EACE,iBAAgB;EAChB,gBAAe;E7BTb,iB6BUsB;CACzB;;ACXD;EACE,yBpCivBmC;EoChvBnC,oBpCivBgC;EoChvBhC,8BAA6C;E9BH3C,uBNmN2B;CoC9M9B;;AAGD;EAEE,eAAc;CACf;;AAGD;EACE,kBpCgOqB;CoC/NtB;;AAOD;EAGI,mBAAkB;EAClB,cpCstBgC;EoCrtBhC,gBpCstBiC;EoCrtBjC,yBpCqtBiC;EoCptBjC,eAAc;CACf;;AASD;EC3CA,etBsFkE;EsBrFlE,0BtBmFuE;EsBlFvE,sBtBkFuE;CqBvCtE;;ACzCD;EACE,0BAAqC;CACtC;;AAED;EACE,eAA0B;CAC3B;;ADiCD;EC3CA,etBsFkE;EsBrFlE,0BtBmFuE;EsBlFvE,sBtBkFuE;CqBvCtE;;ACzCD;EACE,0BAAqC;CACtC;;AAED;EACE,eAA0B;CAC3B;;ADiCD;EC3CA,etBsFkE;EsBrFlE,0BtBmFuE;EsBlFvE,sBtBkFuE;CqBvCtE;;ACzCD;EACE,0BAAqC;CACtC;;AAED;EACE,eAA0B;CAC3B;;ADiCD;EC3CA,etBsFkE;EsBrFlE,0BtBmFuE;EsBlFvE,sBtBkFuE;CqBvCtE;;ACzCD;EACE,0BAAqC;CACtC;;AAED;EACE,eAA0B;CAC3B;;ADiCD;EC3CA,etBsFkE;EsBrFlE,0BtBmFuE;EsBlFvE,sBtBkFuE;CqBvCtE;;ACzCD;EACE,0BAAqC;CACtC;;AAED;EACE,eAA0B;CAC3B;;ADiCD;EC3CA,etBsFkE;EsBrFlE,0BtBmFuE;EsBlFvE,sBtBkFuE;CqBvCtE;;ACzCD;EACE,0BAAqC;CACtC;;AAED;EACE,eAA0B;CAC3B;;ADiCD;EC3CA,etBsFkE;EsBrFlE,0BtBmFuE;EsBlFvE,sBtBkFuE;CqBvCtE;;ACzCD;EACE,0BAAqC;CACtC;;AAED;EACE,eAA0B;CAC3B;;ADiCD;EC3CA,etBsFkE;EsBrFlE,0BtBmFuE;EsBlFvE,sBtBkFuE;CqBvCtE;;ACzCD;EACE,0BAAqC;CACtC;;AAED;EACE,eAA0B;CAC3B;;ACXH;EACE;IAAO,4BAAuC;GxCy4H7C;EwCx4HD;IAAK,yBAAwB;GxC24H5B;CACF;;AwC94HD;EACE;IAAO,4BAAuC;GxCy4H7C;EwCx4HD;IAAK,yBAAwB;GxC24H5B;CACF;;AwCz4HD;EACE,qBAAa;EAAb,cAAa;EACb,iBAAgB;EAChB,mBtCwvBoC;EsCvvBpC,kBtCsvBkC;EsCrvBlC,mBAAkB;EAClB,0BtCyCgB;EMhDd,uBNmN2B;CsCzM9B;;AAED;EACE,atC8uBkC;EsC7uBlC,kBtC6uBkC;EsC5uBlC,YtC+BW;EsC9BX,0BtCsDe;EOrEX,4BPkwBwC;CsCjvB7C;;AAED;ECWE,sMAA6I;EDT7I,2BtCquBkC;CsCpuBnC;;AAED;EACE,2DtCwuBgD;UsCxuBhD,mDtCwuBgD;CsCvuBjD;;AE/BD;EACE,qBAAa;EAAb,cAAa;EACb,sBAAuB;MAAvB,wBAAuB;CACxB;;AAED;EACE,YAAO;MAAP,QAAO;CACR;;ACHD;EACE,qBAAa;EAAb,cAAa;EACb,2BAAsB;MAAtB,uBAAsB;EAGtB,gBAAe;EACf,iBAAgB;CACjB;;AAQD;EACE,YAAW;EACX,ezCoCgB;EyCnChB,oBAAmB;CAapB;;AxCbG;EwCIA,ezC+Bc;EyC9Bd,sBAAqB;EACrB,0BzCuBc;CC1Bb;;AwCNL;EAaI,ezC2Bc;EyC1Bd,0BzCmBc;CyClBf;;AAQH;EACE,mBAAkB;EAClB,eAAc;EACd,yBzCquBsC;EyCnuBtC,oBzCsKgB;EyCrKhB,uBzCEW;EyCDX,uCzCWW;CyCiBZ;;AAnCD;EnChCI,gCN6M2B;EM5M3B,iCN4M2B;CyClK5B;;AAXH;EAcI,iBAAgB;EnChChB,oCN+L2B;EM9L3B,mCN8L2B;CyC7J5B;;AxCpCC;EwCuCA,sBAAqB;CxCpCpB;;AwCiBL;EAwBI,ezCVc;EyCWd,uBzCjBS;CyCkBV;;AA1BH;EA8BI,WAAU;EACV,YzCvBS;EyCwBT,0BzCAa;EyCCb,sBzCDa;CyCEd;;AASH;EAEI,gBAAe;EACf,eAAc;EACd,iBAAgB;CACjB;;AALH;EASM,cAAa;CACd;;AAVL;EAeM,iBAAgB;CACjB;;AClGH;EACE,e3BmFgE;E2BlFhE,0B3BgFqE;C2B/EtE;;AAGD;;EAEE,e3B4EgE;C2BhEjE;;AzCDC;;;EyCRE,e3ByE8D;E2BxE9D,0BAAyC;CzCU1C;;AyChBH;;EAUI,YAAW;EACX,0B3BmE8D;E2BlE9D,sB3BkE8D;C2BjE/D;;AAnBH;EACE,e3BmFgE;E2BlFhE,0B3BgFqE;C2B/EtE;;AAGD;;EAEE,e3B4EgE;C2BhEjE;;AzCDC;;;EyCRE,e3ByE8D;E2BxE9D,0BAAyC;CzCU1C;;AyChBH;;EAUI,YAAW;EACX,0B3BmE8D;E2BlE9D,sB3BkE8D;C2BjE/D;;AAnBH;EACE,e3BmFgE;E2BlFhE,0B3BgFqE;C2B/EtE;;AAGD;;EAEE,e3B4EgE;C2BhEjE;;AzCDC;;;EyCRE,e3ByE8D;E2BxE9D,0BAAyC;CzCU1C;;AyChBH;;EAUI,YAAW;EACX,0B3BmE8D;E2BlE9D,sB3BkE8D;C2BjE/D;;AAnBH;EACE,e3BmFgE;E2BlFhE,0B3BgFqE;C2B/EtE;;AAGD;;EAEE,e3B4EgE;C2BhEjE;;AzCDC;;;EyCRE,e3ByE8D;E2BxE9D,0BAAyC;CzCU1C;;AyChBH;;EAUI,YAAW;EACX,0B3BmE8D;E2BlE9D,sB3BkE8D;C2BjE/D;;AAnBH;EACE,e3BmFgE;E2BlFhE,0B3BgFqE;C2B/EtE;;AAGD;;EAEE,e3B4EgE;C2BhEjE;;AzCDC;;;EyCRE,e3ByE8D;E2BxE9D,0BAAyC;CzCU1C;;AyChBH;;EAUI,YAAW;EACX,0B3BmE8D;E2BlE9D,sB3BkE8D;C2BjE/D;;AAnBH;EACE,e3BmFgE;E2BlFhE,0B3BgFqE;C2B/EtE;;AAGD;;EAEE,e3B4EgE;C2BhEjE;;AzCDC;;;EyCRE,e3ByE8D;E2BxE9D,0BAAyC;CzCU1C;;AyChBH;;EAUI,YAAW;EACX,0B3BmE8D;E2BlE9D,sB3BkE8D;C2BjE/D;;AAnBH;EACE,e3BmFgE;E2BlFhE,0B3BgFqE;C2B/EtE;;AAGD;;EAEE,e3B4EgE;C2BhEjE;;AzCDC;;;EyCRE,e3ByE8D;E2BxE9D,0BAAyC;CzCU1C;;AyChBH;;EAUI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","file":"bootstrap.css","sourcesContent":[null,null,"/*!\n * Bootstrap v4.0.0-alpha.6 (https://getbootstrap.com)\n * Copyright 2011-2017 The Bootstrap Authors\n * Copyright 2011-2017 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n@media print {\n *,\n *::before,\n *::after,\n p::first-letter,\n div::first-letter,\n blockquote::first-letter,\n li::first-letter,\n p::first-line,\n div::first-line,\n blockquote::first-line,\n li::first-line {\n text-shadow: none !important;\n box-shadow: none !important;\n }\n a,\n a:visited {\n text-decoration: underline;\n }\n abbr[title]::after {\n content: \" (\" attr(title) \")\";\n }\n pre {\n white-space: pre-wrap !important;\n }\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n thead {\n display: table-header-group;\n }\n tr,\n img {\n page-break-inside: avoid;\n }\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n h2,\n h3 {\n page-break-after: avoid;\n }\n .navbar {\n display: none;\n }\n .badge {\n border: 1px solid #000;\n }\n .table {\n border-collapse: collapse !important;\n }\n .table td,\n .table th {\n background-color: #fff !important;\n }\n .table-bordered th,\n .table-bordered td {\n border: 1px solid #ddd !important;\n }\n}\n\nhtml {\n box-sizing: border-box;\n font-family: sans-serif;\n line-height: 1.15;\n -webkit-text-size-adjust: 100%;\n -ms-text-size-adjust: 100%;\n -ms-overflow-style: scrollbar;\n -webkit-tap-highlight-color: transparent;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: inherit;\n}\n\n@-ms-viewport {\n width: device-width;\n}\n\narticle, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {\n display: block;\n}\n\nbody {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n font-size: 1rem;\n font-weight: normal;\n line-height: 1.5;\n color: #212529;\n background-color: #fff;\n}\n\n[tabindex=\"-1\"]:focus {\n outline: none !important;\n}\n\nhr {\n box-sizing: content-box;\n height: 0;\n overflow: visible;\n}\n\nh1, h2, h3, h4, h5, h6 {\n margin-top: 0;\n margin-bottom: .5rem;\n}\n\np {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nabbr[title],\nabbr[data-original-title] {\n text-decoration: underline;\n text-decoration: underline dotted;\n cursor: help;\n border-bottom: 0;\n}\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: bold;\n}\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0;\n}\n\nblockquote {\n margin: 0 0 1rem;\n}\n\ndfn {\n font-style: italic;\n}\n\nb,\nstrong {\n font-weight: bolder;\n}\n\nsmall {\n font-size: 80%;\n}\n\nsub,\nsup {\n position: relative;\n font-size: 75%;\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -.25em;\n}\n\nsup {\n top: -.5em;\n}\n\na {\n color: #007bff;\n text-decoration: none;\n background-color: transparent;\n -webkit-text-decoration-skip: objects;\n}\n\na:hover {\n color: #0056b3;\n text-decoration: underline;\n}\n\na:not([href]):not([tabindex]) {\n color: inherit;\n text-decoration: none;\n}\n\na:not([href]):not([tabindex]):focus, a:not([href]):not([tabindex]):hover {\n color: inherit;\n text-decoration: none;\n}\n\na:not([href]):not([tabindex]):focus {\n outline: 0;\n}\n\npre,\ncode,\nkbd,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\n\npre {\n margin-top: 0;\n margin-bottom: 1rem;\n overflow: auto;\n}\n\nfigure {\n margin: 0 0 1rem;\n}\n\nimg {\n vertical-align: middle;\n border-style: none;\n}\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\na,\narea,\nbutton,\n[role=\"button\"],\ninput,\nlabel,\nselect,\nsummary,\ntextarea {\n touch-action: manipulation;\n}\n\ntable {\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: 0.75rem;\n padding-bottom: 0.75rem;\n color: #868e96;\n text-align: left;\n caption-side: bottom;\n}\n\nth {\n text-align: left;\n}\n\nlabel {\n display: inline-block;\n margin-bottom: .5rem;\n}\n\nbutton:focus {\n outline: 1px dotted;\n outline: 5px auto -webkit-focus-ring-color;\n}\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\nbutton,\ninput {\n overflow: visible;\n}\n\nbutton,\nselect {\n text-transform: none;\n}\n\nbutton,\nhtml [type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button;\n}\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n box-sizing: border-box;\n padding: 0;\n}\n\ninput[type=\"date\"],\ninput[type=\"time\"],\ninput[type=\"datetime-local\"],\ninput[type=\"month\"] {\n -webkit-appearance: listbox;\n}\n\ntextarea {\n overflow: auto;\n resize: vertical;\n}\n\nfieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n max-width: 100%;\n padding: 0;\n margin-bottom: .5rem;\n font-size: 1.5rem;\n line-height: inherit;\n color: inherit;\n white-space: normal;\n}\n\nprogress {\n vertical-align: baseline;\n}\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n[type=\"search\"] {\n outline-offset: -2px;\n -webkit-appearance: none;\n}\n\n[type=\"search\"]::-webkit-search-cancel-button,\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n::-webkit-file-upload-button {\n font: inherit;\n -webkit-appearance: button;\n}\n\noutput {\n display: inline-block;\n}\n\nsummary {\n display: list-item;\n}\n\ntemplate {\n display: none;\n}\n\n[hidden] {\n display: none !important;\n}\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n margin-bottom: 0.5rem;\n font-family: inherit;\n font-weight: 500;\n line-height: 1.1;\n color: inherit;\n}\n\nh1, .h1 {\n font-size: 2.5rem;\n}\n\nh2, .h2 {\n font-size: 2rem;\n}\n\nh3, .h3 {\n font-size: 1.75rem;\n}\n\nh4, .h4 {\n font-size: 1.5rem;\n}\n\nh5, .h5 {\n font-size: 1.25rem;\n}\n\nh6, .h6 {\n font-size: 1rem;\n}\n\n.lead {\n font-size: 1.25rem;\n font-weight: 300;\n}\n\n.display-1 {\n font-size: 6rem;\n font-weight: 300;\n line-height: 1.1;\n}\n\n.display-2 {\n font-size: 5.5rem;\n font-weight: 300;\n line-height: 1.1;\n}\n\n.display-3 {\n font-size: 4.5rem;\n font-weight: 300;\n line-height: 1.1;\n}\n\n.display-4 {\n font-size: 3.5rem;\n font-weight: 300;\n line-height: 1.1;\n}\n\nhr {\n margin-top: 1rem;\n margin-bottom: 1rem;\n border: 0;\n border-top: 1px solid rgba(0, 0, 0, 0.1);\n}\n\nsmall,\n.small {\n font-size: 80%;\n font-weight: normal;\n}\n\nmark,\n.mark {\n padding: 0.2em;\n background-color: #fcf8e3;\n}\n\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n\n.list-inline {\n padding-left: 0;\n list-style: none;\n}\n\n.list-inline-item {\n display: inline-block;\n}\n\n.list-inline-item:not(:last-child) {\n margin-right: 5px;\n}\n\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\n\n.blockquote {\n margin-bottom: 1rem;\n font-size: 1.25rem;\n}\n\n.blockquote-footer {\n display: block;\n font-size: 80%;\n color: #868e96;\n}\n\n.blockquote-footer::before {\n content: \"\\2014 \\00A0\";\n}\n\n.img-fluid {\n max-width: 100%;\n height: auto;\n}\n\n.img-thumbnail {\n padding: 0.25rem;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 0.25rem;\n transition: all 0.2s ease-in-out;\n max-width: 100%;\n height: auto;\n}\n\n.figure {\n display: inline-block;\n}\n\n.figure-img {\n margin-bottom: 0.5rem;\n line-height: 1;\n}\n\n.figure-caption {\n font-size: 90%;\n color: #868e96;\n}\n\ncode,\nkbd,\npre,\nsamp {\n font-family: Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n}\n\ncode {\n padding: 0.2rem 0.4rem;\n font-size: 90%;\n color: #bd4147;\n background-color: #f8f9fa;\n border-radius: 0.25rem;\n}\n\na > code {\n padding: 0;\n color: inherit;\n background-color: inherit;\n}\n\nkbd {\n padding: 0.2rem 0.4rem;\n font-size: 90%;\n color: #fff;\n background-color: #212529;\n border-radius: 0.2rem;\n}\n\nkbd kbd {\n padding: 0;\n font-size: 100%;\n font-weight: bold;\n}\n\npre {\n display: block;\n margin-top: 0;\n margin-bottom: 1rem;\n font-size: 90%;\n color: #212529;\n}\n\npre code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n background-color: transparent;\n border-radius: 0;\n}\n\n.pre-scrollable {\n max-height: 340px;\n overflow-y: scroll;\n}\n\n.container {\n margin-right: auto;\n margin-left: auto;\n padding-right: 15px;\n padding-left: 15px;\n}\n\n@media (min-width: 576px) {\n .container {\n width: 540px;\n max-width: 100%;\n }\n}\n\n@media (min-width: 768px) {\n .container {\n width: 720px;\n max-width: 100%;\n }\n}\n\n@media (min-width: 992px) {\n .container {\n width: 960px;\n max-width: 100%;\n }\n}\n\n@media (min-width: 1200px) {\n .container {\n width: 1140px;\n max-width: 100%;\n }\n}\n\n.container-fluid {\n width: 100%;\n margin-right: auto;\n margin-left: auto;\n padding-right: 15px;\n padding-left: 15px;\n}\n\n.row {\n display: flex;\n flex-wrap: wrap;\n margin-right: -15px;\n margin-left: -15px;\n}\n\n.no-gutters {\n margin-right: 0;\n margin-left: 0;\n}\n\n.no-gutters > .col,\n.no-gutters > [class*=\"col-\"] {\n padding-right: 0;\n padding-left: 0;\n}\n\n.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, .col,\n.col-auto, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm,\n.col-sm-auto, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md,\n.col-md-auto, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg,\n.col-lg-auto, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl,\n.col-xl-auto {\n position: relative;\n width: 100%;\n min-height: 1px;\n padding-right: 15px;\n padding-left: 15px;\n}\n\n.col {\n flex-basis: 0;\n flex-grow: 1;\n max-width: 100%;\n}\n\n.col-auto {\n flex: 0 0 auto;\n width: auto;\n max-width: none;\n}\n\n.col-1 {\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n}\n\n.col-2 {\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n}\n\n.col-3 {\n flex: 0 0 25%;\n max-width: 25%;\n}\n\n.col-4 {\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n}\n\n.col-5 {\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n}\n\n.col-6 {\n flex: 0 0 50%;\n max-width: 50%;\n}\n\n.col-7 {\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n}\n\n.col-8 {\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n}\n\n.col-9 {\n flex: 0 0 75%;\n max-width: 75%;\n}\n\n.col-10 {\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n}\n\n.col-11 {\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n}\n\n.col-12 {\n flex: 0 0 100%;\n max-width: 100%;\n}\n\n.order-1 {\n order: 1;\n}\n\n.order-2 {\n order: 2;\n}\n\n.order-3 {\n order: 3;\n}\n\n.order-4 {\n order: 4;\n}\n\n.order-5 {\n order: 5;\n}\n\n.order-6 {\n order: 6;\n}\n\n.order-7 {\n order: 7;\n}\n\n.order-8 {\n order: 8;\n}\n\n.order-9 {\n order: 9;\n}\n\n.order-10 {\n order: 10;\n}\n\n.order-11 {\n order: 11;\n}\n\n.order-12 {\n order: 12;\n}\n\n@media (min-width: 576px) {\n .col-sm {\n flex-basis: 0;\n flex-grow: 1;\n max-width: 100%;\n }\n .col-sm-auto {\n flex: 0 0 auto;\n width: auto;\n max-width: none;\n }\n .col-sm-1 {\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n }\n .col-sm-2 {\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n }\n .col-sm-3 {\n flex: 0 0 25%;\n max-width: 25%;\n }\n .col-sm-4 {\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n }\n .col-sm-5 {\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n }\n .col-sm-6 {\n flex: 0 0 50%;\n max-width: 50%;\n }\n .col-sm-7 {\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n }\n .col-sm-8 {\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n }\n .col-sm-9 {\n flex: 0 0 75%;\n max-width: 75%;\n }\n .col-sm-10 {\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n }\n .col-sm-11 {\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n }\n .col-sm-12 {\n flex: 0 0 100%;\n max-width: 100%;\n }\n .order-sm-1 {\n order: 1;\n }\n .order-sm-2 {\n order: 2;\n }\n .order-sm-3 {\n order: 3;\n }\n .order-sm-4 {\n order: 4;\n }\n .order-sm-5 {\n order: 5;\n }\n .order-sm-6 {\n order: 6;\n }\n .order-sm-7 {\n order: 7;\n }\n .order-sm-8 {\n order: 8;\n }\n .order-sm-9 {\n order: 9;\n }\n .order-sm-10 {\n order: 10;\n }\n .order-sm-11 {\n order: 11;\n }\n .order-sm-12 {\n order: 12;\n }\n}\n\n@media (min-width: 768px) {\n .col-md {\n flex-basis: 0;\n flex-grow: 1;\n max-width: 100%;\n }\n .col-md-auto {\n flex: 0 0 auto;\n width: auto;\n max-width: none;\n }\n .col-md-1 {\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n }\n .col-md-2 {\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n }\n .col-md-3 {\n flex: 0 0 25%;\n max-width: 25%;\n }\n .col-md-4 {\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n }\n .col-md-5 {\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n }\n .col-md-6 {\n flex: 0 0 50%;\n max-width: 50%;\n }\n .col-md-7 {\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n }\n .col-md-8 {\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n }\n .col-md-9 {\n flex: 0 0 75%;\n max-width: 75%;\n }\n .col-md-10 {\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n }\n .col-md-11 {\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n }\n .col-md-12 {\n flex: 0 0 100%;\n max-width: 100%;\n }\n .order-md-1 {\n order: 1;\n }\n .order-md-2 {\n order: 2;\n }\n .order-md-3 {\n order: 3;\n }\n .order-md-4 {\n order: 4;\n }\n .order-md-5 {\n order: 5;\n }\n .order-md-6 {\n order: 6;\n }\n .order-md-7 {\n order: 7;\n }\n .order-md-8 {\n order: 8;\n }\n .order-md-9 {\n order: 9;\n }\n .order-md-10 {\n order: 10;\n }\n .order-md-11 {\n order: 11;\n }\n .order-md-12 {\n order: 12;\n }\n}\n\n@media (min-width: 992px) {\n .col-lg {\n flex-basis: 0;\n flex-grow: 1;\n max-width: 100%;\n }\n .col-lg-auto {\n flex: 0 0 auto;\n width: auto;\n max-width: none;\n }\n .col-lg-1 {\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n }\n .col-lg-2 {\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n }\n .col-lg-3 {\n flex: 0 0 25%;\n max-width: 25%;\n }\n .col-lg-4 {\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n }\n .col-lg-5 {\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n }\n .col-lg-6 {\n flex: 0 0 50%;\n max-width: 50%;\n }\n .col-lg-7 {\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n }\n .col-lg-8 {\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n }\n .col-lg-9 {\n flex: 0 0 75%;\n max-width: 75%;\n }\n .col-lg-10 {\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n }\n .col-lg-11 {\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n }\n .col-lg-12 {\n flex: 0 0 100%;\n max-width: 100%;\n }\n .order-lg-1 {\n order: 1;\n }\n .order-lg-2 {\n order: 2;\n }\n .order-lg-3 {\n order: 3;\n }\n .order-lg-4 {\n order: 4;\n }\n .order-lg-5 {\n order: 5;\n }\n .order-lg-6 {\n order: 6;\n }\n .order-lg-7 {\n order: 7;\n }\n .order-lg-8 {\n order: 8;\n }\n .order-lg-9 {\n order: 9;\n }\n .order-lg-10 {\n order: 10;\n }\n .order-lg-11 {\n order: 11;\n }\n .order-lg-12 {\n order: 12;\n }\n}\n\n@media (min-width: 1200px) {\n .col-xl {\n flex-basis: 0;\n flex-grow: 1;\n max-width: 100%;\n }\n .col-xl-auto {\n flex: 0 0 auto;\n width: auto;\n max-width: none;\n }\n .col-xl-1 {\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n }\n .col-xl-2 {\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n }\n .col-xl-3 {\n flex: 0 0 25%;\n max-width: 25%;\n }\n .col-xl-4 {\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n }\n .col-xl-5 {\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n }\n .col-xl-6 {\n flex: 0 0 50%;\n max-width: 50%;\n }\n .col-xl-7 {\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n }\n .col-xl-8 {\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n }\n .col-xl-9 {\n flex: 0 0 75%;\n max-width: 75%;\n }\n .col-xl-10 {\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n }\n .col-xl-11 {\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n }\n .col-xl-12 {\n flex: 0 0 100%;\n max-width: 100%;\n }\n .order-xl-1 {\n order: 1;\n }\n .order-xl-2 {\n order: 2;\n }\n .order-xl-3 {\n order: 3;\n }\n .order-xl-4 {\n order: 4;\n }\n .order-xl-5 {\n order: 5;\n }\n .order-xl-6 {\n order: 6;\n }\n .order-xl-7 {\n order: 7;\n }\n .order-xl-8 {\n order: 8;\n }\n .order-xl-9 {\n order: 9;\n }\n .order-xl-10 {\n order: 10;\n }\n .order-xl-11 {\n order: 11;\n }\n .order-xl-12 {\n order: 12;\n }\n}\n\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: 1rem;\n background-color: transparent;\n}\n\n.table th,\n.table td {\n padding: 0.75rem;\n vertical-align: top;\n border-top: 1px solid #e9ecef;\n}\n\n.table thead th {\n vertical-align: bottom;\n border-bottom: 2px solid #e9ecef;\n}\n\n.table tbody + tbody {\n border-top: 2px solid #e9ecef;\n}\n\n.table .table {\n background-color: #fff;\n}\n\n.table-sm th,\n.table-sm td {\n padding: 0.3rem;\n}\n\n.table-bordered {\n border: 1px solid #e9ecef;\n}\n\n.table-bordered th,\n.table-bordered td {\n border: 1px solid #e9ecef;\n}\n\n.table-bordered thead th,\n.table-bordered thead td {\n border-bottom-width: 2px;\n}\n\n.table-striped tbody tr:nth-of-type(odd) {\n background-color: rgba(0, 0, 0, 0.05);\n}\n\n.table-hover tbody tr:hover {\n background-color: rgba(0, 0, 0, 0.075);\n}\n\n.table-primary,\n.table-primary > th,\n.table-primary > td {\n background-color: #b8daff;\n}\n\n.table-hover .table-primary:hover {\n background-color: #9fcdff;\n}\n\n.table-hover .table-primary:hover > td,\n.table-hover .table-primary:hover > th {\n background-color: #9fcdff;\n}\n\n.table-secondary,\n.table-secondary > th,\n.table-secondary > td {\n background-color: #dddfe2;\n}\n\n.table-hover .table-secondary:hover {\n background-color: #cfd2d6;\n}\n\n.table-hover .table-secondary:hover > td,\n.table-hover .table-secondary:hover > th {\n background-color: #cfd2d6;\n}\n\n.table-success,\n.table-success > th,\n.table-success > td {\n background-color: #c3e6cb;\n}\n\n.table-hover .table-success:hover {\n background-color: #b1dfbb;\n}\n\n.table-hover .table-success:hover > td,\n.table-hover .table-success:hover > th {\n background-color: #b1dfbb;\n}\n\n.table-info,\n.table-info > th,\n.table-info > td {\n background-color: #bee5eb;\n}\n\n.table-hover .table-info:hover {\n background-color: #abdde5;\n}\n\n.table-hover .table-info:hover > td,\n.table-hover .table-info:hover > th {\n background-color: #abdde5;\n}\n\n.table-warning,\n.table-warning > th,\n.table-warning > td {\n background-color: #ffeeba;\n}\n\n.table-hover .table-warning:hover {\n background-color: #ffe8a1;\n}\n\n.table-hover .table-warning:hover > td,\n.table-hover .table-warning:hover > th {\n background-color: #ffe8a1;\n}\n\n.table-danger,\n.table-danger > th,\n.table-danger > td {\n background-color: #f5c6cb;\n}\n\n.table-hover .table-danger:hover {\n background-color: #f1b0b7;\n}\n\n.table-hover .table-danger:hover > td,\n.table-hover .table-danger:hover > th {\n background-color: #f1b0b7;\n}\n\n.table-light,\n.table-light > th,\n.table-light > td {\n background-color: #fdfdfe;\n}\n\n.table-hover .table-light:hover {\n background-color: #ececf6;\n}\n\n.table-hover .table-light:hover > td,\n.table-hover .table-light:hover > th {\n background-color: #ececf6;\n}\n\n.table-dark,\n.table-dark > th,\n.table-dark > td {\n background-color: #c6c8ca;\n}\n\n.table-hover .table-dark:hover {\n background-color: #b9bbbe;\n}\n\n.table-hover .table-dark:hover > td,\n.table-hover .table-dark:hover > th {\n background-color: #b9bbbe;\n}\n\n.thead-inverse th {\n color: #fff;\n background-color: #212529;\n}\n\n.thead-default th {\n color: #495057;\n background-color: #e9ecef;\n}\n\n.table-inverse {\n color: #fff;\n background-color: #212529;\n}\n\n.table-inverse th,\n.table-inverse td,\n.table-inverse thead th {\n border-color: #32383e;\n}\n\n.table-inverse.table-bordered {\n border: 0;\n}\n\n.table-inverse.table-striped tbody tr:nth-of-type(odd) {\n background-color: rgba(255, 255, 255, 0.05);\n}\n\n.table-inverse.table-hover tbody tr:hover {\n background-color: rgba(255, 255, 255, 0.075);\n}\n\n@media (max-width: 991px) {\n .table-responsive {\n display: block;\n width: 100%;\n overflow-x: auto;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n }\n .table-responsive.table-bordered {\n border: 0;\n }\n}\n\n.form-control {\n display: block;\n width: 100%;\n padding: 0.5rem 0.75rem;\n font-size: 1rem;\n line-height: 1.25;\n color: #495057;\n background-color: #fff;\n background-image: none;\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 0.25rem;\n transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;\n}\n\n.form-control::-ms-expand {\n background-color: transparent;\n border: 0;\n}\n\n.form-control:focus {\n color: #495057;\n background-color: #fff;\n border-color: #80bdff;\n outline: none;\n}\n\n.form-control::placeholder {\n color: #868e96;\n opacity: 1;\n}\n\n.form-control:disabled, .form-control[readonly] {\n background-color: #e9ecef;\n opacity: 1;\n}\n\nselect.form-control:not([size]):not([multiple]) {\n height: calc(2.25rem + 2px);\n}\n\nselect.form-control:focus::-ms-value {\n color: #495057;\n background-color: #fff;\n}\n\n.form-control-file,\n.form-control-range {\n display: block;\n}\n\n.col-form-label {\n padding-top: calc(0.5rem - 1px * 2);\n padding-bottom: calc(0.5rem - 1px * 2);\n margin-bottom: 0;\n}\n\n.col-form-label-lg {\n padding-top: calc(0.5rem - 1px * 2);\n padding-bottom: calc(0.5rem - 1px * 2);\n font-size: 1.25rem;\n}\n\n.col-form-label-sm {\n padding-top: calc(0.25rem - 1px * 2);\n padding-bottom: calc(0.25rem - 1px * 2);\n font-size: 0.875rem;\n}\n\n.col-form-legend {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n margin-bottom: 0;\n font-size: 1rem;\n}\n\n.form-control-plaintext {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n margin-bottom: 0;\n line-height: 1.25;\n border: solid transparent;\n border-width: 1px 0;\n}\n\n.form-control-plaintext.form-control-sm, .input-group-sm > .form-control-plaintext.form-control,\n.input-group-sm > .form-control-plaintext.input-group-addon,\n.input-group-sm > .input-group-btn > .form-control-plaintext.btn, .form-control-plaintext.form-control-lg, .input-group-lg > .form-control-plaintext.form-control,\n.input-group-lg > .form-control-plaintext.input-group-addon,\n.input-group-lg > .input-group-btn > .form-control-plaintext.btn {\n padding-right: 0;\n padding-left: 0;\n}\n\n.form-control-sm, .input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n line-height: 1.5;\n border-radius: 0.2rem;\n}\n\nselect.form-control-sm:not([size]):not([multiple]), .input-group-sm > select.form-control:not([size]):not([multiple]),\n.input-group-sm > select.input-group-addon:not([size]):not([multiple]),\n.input-group-sm > .input-group-btn > select.btn:not([size]):not([multiple]) {\n height: calc(1.8125rem + 2px);\n}\n\n.form-control-lg, .input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n line-height: 1.5;\n border-radius: 0.3rem;\n}\n\nselect.form-control-lg:not([size]):not([multiple]), .input-group-lg > select.form-control:not([size]):not([multiple]),\n.input-group-lg > select.input-group-addon:not([size]):not([multiple]),\n.input-group-lg > .input-group-btn > select.btn:not([size]):not([multiple]) {\n height: calc(2.3125rem + 2px);\n}\n\n.form-group {\n margin-bottom: 1rem;\n}\n\n.form-text {\n display: block;\n margin-top: 0.25rem;\n}\n\n.form-row {\n display: flex;\n flex-wrap: wrap;\n margin-right: -5px;\n margin-left: -5px;\n}\n\n.form-row > .col,\n.form-row > [class*=\"col-\"] {\n padding-right: 5px;\n padding-left: 5px;\n}\n\n.form-check {\n position: relative;\n display: block;\n margin-bottom: 0.5rem;\n}\n\n.form-check.disabled .form-check-label {\n color: #868e96;\n}\n\n.form-check-label {\n padding-left: 1.25rem;\n margin-bottom: 0;\n}\n\n.form-check-input {\n position: absolute;\n margin-top: 0.25rem;\n margin-left: -1.25rem;\n}\n\n.form-check-input:only-child {\n position: static;\n}\n\n.form-check-inline {\n display: inline-block;\n}\n\n.form-check-inline .form-check-label {\n vertical-align: middle;\n}\n\n.form-check-inline + .form-check-inline {\n margin-left: 0.75rem;\n}\n\n.invalid-feedback {\n display: none;\n margin-top: .25rem;\n font-size: .875rem;\n color: #dc3545;\n}\n\n.invalid-tooltip {\n position: absolute;\n top: 100%;\n z-index: 5;\n display: none;\n width: 250px;\n padding: .5rem;\n margin-top: .1rem;\n font-size: .875rem;\n line-height: 1;\n color: #fff;\n background-color: rgba(220, 53, 69, 0.8);\n border-radius: .2rem;\n}\n\n.was-validated .form-control:valid, .form-control.is-valid, .was-validated\n.custom-select:valid,\n.custom-select.is-valid {\n border-color: #28a745;\n}\n\n.was-validated .form-control:valid:focus, .form-control.is-valid:focus, .was-validated\n.custom-select:valid:focus,\n.custom-select.is-valid:focus {\n box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);\n}\n\n.was-validated .form-control:valid ~ .invalid-feedback,\n.was-validated .form-control:valid ~ .invalid-tooltip, .form-control.is-valid ~ .invalid-feedback,\n.form-control.is-valid ~ .invalid-tooltip, .was-validated\n.custom-select:valid ~ .invalid-feedback,\n.was-validated\n.custom-select:valid ~ .invalid-tooltip,\n.custom-select.is-valid ~ .invalid-feedback,\n.custom-select.is-valid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated .form-check-input:valid + .form-check-label, .form-check-input.is-valid + .form-check-label {\n color: #28a745;\n}\n\n.was-validated .custom-control-input:valid ~ .custom-control-indicator, .custom-control-input.is-valid ~ .custom-control-indicator {\n background-color: rgba(40, 167, 69, 0.25);\n}\n\n.was-validated .custom-control-input:valid ~ .custom-control-description, .custom-control-input.is-valid ~ .custom-control-description {\n color: #28a745;\n}\n\n.was-validated .custom-file-input:valid ~ .custom-file-control, .custom-file-input.is-valid ~ .custom-file-control {\n border-color: #28a745;\n}\n\n.was-validated .custom-file-input:valid ~ .custom-file-control::before, .custom-file-input.is-valid ~ .custom-file-control::before {\n border-color: inherit;\n}\n\n.was-validated .custom-file-input:valid:focus, .custom-file-input.is-valid:focus {\n box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);\n}\n\n.was-validated .form-control:invalid, .form-control.is-invalid, .was-validated\n.custom-select:invalid,\n.custom-select.is-invalid {\n border-color: #dc3545;\n}\n\n.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus, .was-validated\n.custom-select:invalid:focus,\n.custom-select.is-invalid:focus {\n box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);\n}\n\n.was-validated .form-control:invalid ~ .invalid-feedback,\n.was-validated .form-control:invalid ~ .invalid-tooltip, .form-control.is-invalid ~ .invalid-feedback,\n.form-control.is-invalid ~ .invalid-tooltip, .was-validated\n.custom-select:invalid ~ .invalid-feedback,\n.was-validated\n.custom-select:invalid ~ .invalid-tooltip,\n.custom-select.is-invalid ~ .invalid-feedback,\n.custom-select.is-invalid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated .form-check-input:invalid + .form-check-label, .form-check-input.is-invalid + .form-check-label {\n color: #dc3545;\n}\n\n.was-validated .custom-control-input:invalid ~ .custom-control-indicator, .custom-control-input.is-invalid ~ .custom-control-indicator {\n background-color: rgba(220, 53, 69, 0.25);\n}\n\n.was-validated .custom-control-input:invalid ~ .custom-control-description, .custom-control-input.is-invalid ~ .custom-control-description {\n color: #dc3545;\n}\n\n.was-validated .custom-file-input:invalid ~ .custom-file-control, .custom-file-input.is-invalid ~ .custom-file-control {\n border-color: #dc3545;\n}\n\n.was-validated .custom-file-input:invalid ~ .custom-file-control::before, .custom-file-input.is-invalid ~ .custom-file-control::before {\n border-color: inherit;\n}\n\n.was-validated .custom-file-input:invalid:focus, .custom-file-input.is-invalid:focus {\n box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);\n}\n\n.form-inline {\n display: flex;\n flex-flow: row wrap;\n align-items: center;\n}\n\n.form-inline .form-check {\n width: 100%;\n}\n\n@media (min-width: 576px) {\n .form-inline label {\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 0;\n }\n .form-inline .form-group {\n display: flex;\n flex: 0 0 auto;\n flex-flow: row wrap;\n align-items: center;\n margin-bottom: 0;\n }\n .form-inline .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .form-inline .form-control-plaintext {\n display: inline-block;\n }\n .form-inline .input-group {\n width: auto;\n }\n .form-inline .form-control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .form-check {\n display: flex;\n align-items: center;\n justify-content: center;\n width: auto;\n margin-top: 0;\n margin-bottom: 0;\n }\n .form-inline .form-check-label {\n padding-left: 0;\n }\n .form-inline .form-check-input {\n position: relative;\n margin-top: 0;\n margin-right: 0.25rem;\n margin-left: 0;\n }\n .form-inline .custom-control {\n display: flex;\n align-items: center;\n justify-content: center;\n padding-left: 0;\n }\n .form-inline .custom-control-indicator {\n position: static;\n display: inline-block;\n margin-right: 0.25rem;\n vertical-align: text-bottom;\n }\n .form-inline .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n\n.btn {\n display: inline-block;\n font-weight: normal;\n text-align: center;\n white-space: nowrap;\n vertical-align: middle;\n user-select: none;\n border: 1px solid transparent;\n padding: 0.5rem 0.75rem;\n font-size: 1rem;\n line-height: 1.25;\n border-radius: 0.25rem;\n transition: all 0.2s ease-in-out;\n}\n\n.btn:focus, .btn:hover {\n text-decoration: none;\n}\n\n.btn:focus, .btn.focus {\n outline: 0;\n box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);\n}\n\n.btn.disabled, .btn:disabled {\n opacity: .65;\n}\n\n.btn:active, .btn.active {\n background-image: none;\n}\n\na.btn.disabled,\nfieldset[disabled] a.btn {\n pointer-events: none;\n}\n\n.btn-primary {\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.btn-primary:hover {\n color: #fff;\n background-color: #0069d9;\n border-color: #0062cc;\n}\n\n.btn-primary:focus, .btn-primary.focus {\n box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.5);\n}\n\n.btn-primary.disabled, .btn-primary:disabled {\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.btn-primary:active, .btn-primary.active,\n.show > .btn-primary.dropdown-toggle {\n background-color: #0069d9;\n background-image: none;\n border-color: #0062cc;\n}\n\n.btn-secondary {\n color: #fff;\n background-color: #868e96;\n border-color: #868e96;\n}\n\n.btn-secondary:hover {\n color: #fff;\n background-color: #727b84;\n border-color: #6c757d;\n}\n\n.btn-secondary:focus, .btn-secondary.focus {\n box-shadow: 0 0 0 3px rgba(134, 142, 150, 0.5);\n}\n\n.btn-secondary.disabled, .btn-secondary:disabled {\n background-color: #868e96;\n border-color: #868e96;\n}\n\n.btn-secondary:active, .btn-secondary.active,\n.show > .btn-secondary.dropdown-toggle {\n background-color: #727b84;\n background-image: none;\n border-color: #6c757d;\n}\n\n.btn-success {\n color: #fff;\n background-color: #28a745;\n border-color: #28a745;\n}\n\n.btn-success:hover {\n color: #fff;\n background-color: #218838;\n border-color: #1e7e34;\n}\n\n.btn-success:focus, .btn-success.focus {\n box-shadow: 0 0 0 3px rgba(40, 167, 69, 0.5);\n}\n\n.btn-success.disabled, .btn-success:disabled {\n background-color: #28a745;\n border-color: #28a745;\n}\n\n.btn-success:active, .btn-success.active,\n.show > .btn-success.dropdown-toggle {\n background-color: #218838;\n background-image: none;\n border-color: #1e7e34;\n}\n\n.btn-info {\n color: #fff;\n background-color: #17a2b8;\n border-color: #17a2b8;\n}\n\n.btn-info:hover {\n color: #fff;\n background-color: #138496;\n border-color: #117a8b;\n}\n\n.btn-info:focus, .btn-info.focus {\n box-shadow: 0 0 0 3px rgba(23, 162, 184, 0.5);\n}\n\n.btn-info.disabled, .btn-info:disabled {\n background-color: #17a2b8;\n border-color: #17a2b8;\n}\n\n.btn-info:active, .btn-info.active,\n.show > .btn-info.dropdown-toggle {\n background-color: #138496;\n background-image: none;\n border-color: #117a8b;\n}\n\n.btn-warning {\n color: #111;\n background-color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-warning:hover {\n color: #111;\n background-color: #e0a800;\n border-color: #d39e00;\n}\n\n.btn-warning:focus, .btn-warning.focus {\n box-shadow: 0 0 0 3px rgba(255, 193, 7, 0.5);\n}\n\n.btn-warning.disabled, .btn-warning:disabled {\n background-color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-warning:active, .btn-warning.active,\n.show > .btn-warning.dropdown-toggle {\n background-color: #e0a800;\n background-image: none;\n border-color: #d39e00;\n}\n\n.btn-danger {\n color: #fff;\n background-color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-danger:hover {\n color: #fff;\n background-color: #c82333;\n border-color: #bd2130;\n}\n\n.btn-danger:focus, .btn-danger.focus {\n box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.5);\n}\n\n.btn-danger.disabled, .btn-danger:disabled {\n background-color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-danger:active, .btn-danger.active,\n.show > .btn-danger.dropdown-toggle {\n background-color: #c82333;\n background-image: none;\n border-color: #bd2130;\n}\n\n.btn-light {\n color: #111;\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-light:hover {\n color: #111;\n background-color: #e2e6ea;\n border-color: #dae0e5;\n}\n\n.btn-light:focus, .btn-light.focus {\n box-shadow: 0 0 0 3px rgba(248, 249, 250, 0.5);\n}\n\n.btn-light.disabled, .btn-light:disabled {\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-light:active, .btn-light.active,\n.show > .btn-light.dropdown-toggle {\n background-color: #e2e6ea;\n background-image: none;\n border-color: #dae0e5;\n}\n\n.btn-dark {\n color: #fff;\n background-color: #343a40;\n border-color: #343a40;\n}\n\n.btn-dark:hover {\n color: #fff;\n background-color: #23272b;\n border-color: #1d2124;\n}\n\n.btn-dark:focus, .btn-dark.focus {\n box-shadow: 0 0 0 3px rgba(52, 58, 64, 0.5);\n}\n\n.btn-dark.disabled, .btn-dark:disabled {\n background-color: #343a40;\n border-color: #343a40;\n}\n\n.btn-dark:active, .btn-dark.active,\n.show > .btn-dark.dropdown-toggle {\n background-color: #23272b;\n background-image: none;\n border-color: #1d2124;\n}\n\n.btn-outline-primary {\n color: #007bff;\n background-color: transparent;\n background-image: none;\n border-color: #007bff;\n}\n\n.btn-outline-primary:hover {\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.btn-outline-primary:focus, .btn-outline-primary.focus {\n box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.5);\n}\n\n.btn-outline-primary.disabled, .btn-outline-primary:disabled {\n color: #007bff;\n background-color: transparent;\n}\n\n.btn-outline-primary:active, .btn-outline-primary.active,\n.show > .btn-outline-primary.dropdown-toggle {\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.btn-outline-secondary {\n color: #868e96;\n background-color: transparent;\n background-image: none;\n border-color: #868e96;\n}\n\n.btn-outline-secondary:hover {\n color: #fff;\n background-color: #868e96;\n border-color: #868e96;\n}\n\n.btn-outline-secondary:focus, .btn-outline-secondary.focus {\n box-shadow: 0 0 0 3px rgba(134, 142, 150, 0.5);\n}\n\n.btn-outline-secondary.disabled, .btn-outline-secondary:disabled {\n color: #868e96;\n background-color: transparent;\n}\n\n.btn-outline-secondary:active, .btn-outline-secondary.active,\n.show > .btn-outline-secondary.dropdown-toggle {\n color: #fff;\n background-color: #868e96;\n border-color: #868e96;\n}\n\n.btn-outline-success {\n color: #28a745;\n background-color: transparent;\n background-image: none;\n border-color: #28a745;\n}\n\n.btn-outline-success:hover {\n color: #fff;\n background-color: #28a745;\n border-color: #28a745;\n}\n\n.btn-outline-success:focus, .btn-outline-success.focus {\n box-shadow: 0 0 0 3px rgba(40, 167, 69, 0.5);\n}\n\n.btn-outline-success.disabled, .btn-outline-success:disabled {\n color: #28a745;\n background-color: transparent;\n}\n\n.btn-outline-success:active, .btn-outline-success.active,\n.show > .btn-outline-success.dropdown-toggle {\n color: #fff;\n background-color: #28a745;\n border-color: #28a745;\n}\n\n.btn-outline-info {\n color: #17a2b8;\n background-color: transparent;\n background-image: none;\n border-color: #17a2b8;\n}\n\n.btn-outline-info:hover {\n color: #fff;\n background-color: #17a2b8;\n border-color: #17a2b8;\n}\n\n.btn-outline-info:focus, .btn-outline-info.focus {\n box-shadow: 0 0 0 3px rgba(23, 162, 184, 0.5);\n}\n\n.btn-outline-info.disabled, .btn-outline-info:disabled {\n color: #17a2b8;\n background-color: transparent;\n}\n\n.btn-outline-info:active, .btn-outline-info.active,\n.show > .btn-outline-info.dropdown-toggle {\n color: #fff;\n background-color: #17a2b8;\n border-color: #17a2b8;\n}\n\n.btn-outline-warning {\n color: #ffc107;\n background-color: transparent;\n background-image: none;\n border-color: #ffc107;\n}\n\n.btn-outline-warning:hover {\n color: #fff;\n background-color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-outline-warning:focus, .btn-outline-warning.focus {\n box-shadow: 0 0 0 3px rgba(255, 193, 7, 0.5);\n}\n\n.btn-outline-warning.disabled, .btn-outline-warning:disabled {\n color: #ffc107;\n background-color: transparent;\n}\n\n.btn-outline-warning:active, .btn-outline-warning.active,\n.show > .btn-outline-warning.dropdown-toggle {\n color: #fff;\n background-color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-outline-danger {\n color: #dc3545;\n background-color: transparent;\n background-image: none;\n border-color: #dc3545;\n}\n\n.btn-outline-danger:hover {\n color: #fff;\n background-color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-outline-danger:focus, .btn-outline-danger.focus {\n box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.5);\n}\n\n.btn-outline-danger.disabled, .btn-outline-danger:disabled {\n color: #dc3545;\n background-color: transparent;\n}\n\n.btn-outline-danger:active, .btn-outline-danger.active,\n.show > .btn-outline-danger.dropdown-toggle {\n color: #fff;\n background-color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-outline-light {\n color: #f8f9fa;\n background-color: transparent;\n background-image: none;\n border-color: #f8f9fa;\n}\n\n.btn-outline-light:hover {\n color: #fff;\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-outline-light:focus, .btn-outline-light.focus {\n box-shadow: 0 0 0 3px rgba(248, 249, 250, 0.5);\n}\n\n.btn-outline-light.disabled, .btn-outline-light:disabled {\n color: #f8f9fa;\n background-color: transparent;\n}\n\n.btn-outline-light:active, .btn-outline-light.active,\n.show > .btn-outline-light.dropdown-toggle {\n color: #fff;\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-outline-dark {\n color: #343a40;\n background-color: transparent;\n background-image: none;\n border-color: #343a40;\n}\n\n.btn-outline-dark:hover {\n color: #fff;\n background-color: #343a40;\n border-color: #343a40;\n}\n\n.btn-outline-dark:focus, .btn-outline-dark.focus {\n box-shadow: 0 0 0 3px rgba(52, 58, 64, 0.5);\n}\n\n.btn-outline-dark.disabled, .btn-outline-dark:disabled {\n color: #343a40;\n background-color: transparent;\n}\n\n.btn-outline-dark:active, .btn-outline-dark.active,\n.show > .btn-outline-dark.dropdown-toggle {\n color: #fff;\n background-color: #343a40;\n border-color: #343a40;\n}\n\n.btn-link {\n font-weight: normal;\n color: #007bff;\n border-radius: 0;\n}\n\n.btn-link, .btn-link:active, .btn-link.active, .btn-link:disabled {\n background-color: transparent;\n}\n\n.btn-link, .btn-link:focus, .btn-link:active {\n border-color: transparent;\n}\n\n.btn-link:hover {\n border-color: transparent;\n}\n\n.btn-link:focus, .btn-link:hover {\n color: #0056b3;\n text-decoration: underline;\n background-color: transparent;\n}\n\n.btn-link:disabled {\n color: #868e96;\n}\n\n.btn-link:disabled:focus, .btn-link:disabled:hover {\n text-decoration: none;\n}\n\n.btn-lg, .btn-group-lg > .btn {\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n line-height: 1.5;\n border-radius: 0.3rem;\n}\n\n.btn-sm, .btn-group-sm > .btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n line-height: 1.5;\n border-radius: 0.2rem;\n}\n\n.btn-block {\n display: block;\n width: 100%;\n}\n\n.btn-block + .btn-block {\n margin-top: 0.5rem;\n}\n\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n width: 100%;\n}\n\n.fade {\n opacity: 0;\n transition: opacity 0.15s linear;\n}\n\n.fade.show {\n opacity: 1;\n}\n\n.collapse {\n display: none;\n}\n\n.collapse.show {\n display: block;\n}\n\ntr.collapse.show {\n display: table-row;\n}\n\ntbody.collapse.show {\n display: table-row-group;\n}\n\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n transition: height 0.35s ease;\n}\n\n.dropup,\n.dropdown {\n position: relative;\n}\n\n.dropdown-toggle::after {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0.3em solid;\n border-right: 0.3em solid transparent;\n border-left: 0.3em solid transparent;\n}\n\n.dropdown-toggle:empty::after {\n margin-left: 0;\n}\n\n.dropup .dropdown-toggle::after {\n border-top: 0;\n border-bottom: 0.3em solid;\n}\n\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 1000;\n display: none;\n float: left;\n min-width: 10rem;\n padding: 0.5rem 0;\n margin: 0.125rem 0 0;\n font-size: 1rem;\n color: #212529;\n text-align: left;\n list-style: none;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 0.25rem;\n}\n\n.dropdown-divider {\n height: 0;\n margin: 0.5rem 0;\n overflow: hidden;\n border-top: 1px solid #e9ecef;\n}\n\n.dropdown-item {\n display: block;\n width: 100%;\n padding: 0.25rem 1.5rem;\n clear: both;\n font-weight: normal;\n color: #212529;\n text-align: inherit;\n white-space: nowrap;\n background: none;\n border: 0;\n}\n\n.dropdown-item:focus, .dropdown-item:hover {\n color: #16181b;\n text-decoration: none;\n background-color: #f8f9fa;\n}\n\n.dropdown-item.active, .dropdown-item:active {\n color: #fff;\n text-decoration: none;\n background-color: #007bff;\n}\n\n.dropdown-item.disabled, .dropdown-item:disabled {\n color: #868e96;\n background-color: transparent;\n}\n\n.show > a {\n outline: 0;\n}\n\n.dropdown-menu.show {\n display: block;\n}\n\n.dropdown-header {\n display: block;\n padding: 0.5rem 1.5rem;\n margin-bottom: 0;\n font-size: 0.875rem;\n color: #868e96;\n white-space: nowrap;\n}\n\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-flex;\n vertical-align: middle;\n}\n\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n flex: 0 1 auto;\n margin-bottom: 0;\n}\n\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover {\n z-index: 2;\n}\n\n.btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active,\n.btn-group-vertical > .btn:focus,\n.btn-group-vertical > .btn:active,\n.btn-group-vertical > .btn.active {\n z-index: 2;\n}\n\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group,\n.btn-group-vertical .btn + .btn,\n.btn-group-vertical .btn + .btn-group,\n.btn-group-vertical .btn-group + .btn,\n.btn-group-vertical .btn-group + .btn-group {\n margin-left: -1px;\n}\n\n.btn-toolbar {\n display: flex;\n flex-wrap: wrap;\n justify-content: flex-start;\n}\n\n.btn-toolbar .input-group {\n width: auto;\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n\n.btn-group > .btn:first-child {\n margin-left: 0;\n}\n\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.btn-group > .btn-group {\n float: left;\n}\n\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.btn + .dropdown-toggle-split {\n padding-right: 0.5625rem;\n padding-left: 0.5625rem;\n}\n\n.btn + .dropdown-toggle-split::after {\n margin-left: 0;\n}\n\n.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split {\n padding-right: 0.375rem;\n padding-left: 0.375rem;\n}\n\n.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split {\n padding-right: 0.75rem;\n padding-left: 0.75rem;\n}\n\n.btn-group-vertical {\n display: inline-flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: center;\n}\n\n.btn-group-vertical .btn,\n.btn-group-vertical .btn-group {\n width: 100%;\n}\n\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n}\n\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n\n.input-group {\n position: relative;\n display: flex;\n width: 100%;\n}\n\n.input-group .form-control {\n position: relative;\n z-index: 2;\n flex: 1 1 auto;\n width: 1%;\n margin-bottom: 0;\n}\n\n.input-group .form-control:focus, .input-group .form-control:active, .input-group .form-control:hover {\n z-index: 3;\n}\n\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: flex;\n align-items: center;\n}\n\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n\n.input-group-addon,\n.input-group-btn {\n white-space: nowrap;\n vertical-align: middle;\n}\n\n.input-group-addon {\n padding: 0.5rem 0.75rem;\n margin-bottom: 0;\n font-size: 1rem;\n font-weight: normal;\n line-height: 1.25;\n color: #495057;\n text-align: center;\n background-color: #e9ecef;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 0.25rem;\n}\n\n.input-group-addon.form-control-sm,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .input-group-addon.btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n border-radius: 0.2rem;\n}\n\n.input-group-addon.form-control-lg,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .input-group-addon.btn {\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n border-radius: 0.3rem;\n}\n\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n margin-top: 0;\n}\n\n.input-group .form-control:not(:last-child),\n.input-group-addon:not(:last-child),\n.input-group-btn:not(:last-child) > .btn,\n.input-group-btn:not(:last-child) > .btn-group > .btn,\n.input-group-btn:not(:last-child) > .dropdown-toggle,\n.input-group-btn:not(:first-child) > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:not(:first-child) > .btn-group:not(:last-child) > .btn {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n.input-group-addon:not(:last-child) {\n border-right: 0;\n}\n\n.input-group .form-control:not(:first-child),\n.input-group-addon:not(:first-child),\n.input-group-btn:not(:first-child) > .btn,\n.input-group-btn:not(:first-child) > .btn-group > .btn,\n.input-group-btn:not(:first-child) > .dropdown-toggle,\n.input-group-btn:not(:last-child) > .btn:not(:first-child),\n.input-group-btn:not(:last-child) > .btn-group:not(:first-child) > .btn {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.form-control + .input-group-addon:not(:first-child) {\n border-left: 0;\n}\n\n.input-group-btn {\n position: relative;\n font-size: 0;\n white-space: nowrap;\n}\n\n.input-group-btn > .btn {\n position: relative;\n}\n\n.input-group-btn > .btn + .btn {\n margin-left: -1px;\n}\n\n.input-group-btn > .btn:focus, .input-group-btn > .btn:active, .input-group-btn > .btn:hover {\n z-index: 3;\n}\n\n.input-group-btn:not(:last-child) > .btn,\n.input-group-btn:not(:last-child) > .btn-group {\n margin-right: -1px;\n}\n\n.input-group-btn:not(:first-child) > .btn,\n.input-group-btn:not(:first-child) > .btn-group {\n z-index: 2;\n margin-left: -1px;\n}\n\n.input-group-btn:not(:first-child) > .btn:focus, .input-group-btn:not(:first-child) > .btn:active, .input-group-btn:not(:first-child) > .btn:hover,\n.input-group-btn:not(:first-child) > .btn-group:focus,\n.input-group-btn:not(:first-child) > .btn-group:active,\n.input-group-btn:not(:first-child) > .btn-group:hover {\n z-index: 3;\n}\n\n.custom-control {\n position: relative;\n display: inline-flex;\n min-height: 1.5rem;\n padding-left: 1.5rem;\n margin-right: 1rem;\n}\n\n.custom-control-input {\n position: absolute;\n z-index: -1;\n opacity: 0;\n}\n\n.custom-control-input:checked ~ .custom-control-indicator {\n color: #fff;\n background-color: #007bff;\n}\n\n.custom-control-input:focus ~ .custom-control-indicator {\n box-shadow: 0 0 0 1px #fff, 0 0 0 3px #007bff;\n}\n\n.custom-control-input:active ~ .custom-control-indicator {\n color: #fff;\n background-color: #b3d7ff;\n}\n\n.custom-control-input:disabled ~ .custom-control-indicator {\n background-color: #e9ecef;\n}\n\n.custom-control-input:disabled ~ .custom-control-description {\n color: #868e96;\n}\n\n.custom-control-indicator {\n position: absolute;\n top: 0.25rem;\n left: 0;\n display: block;\n width: 1rem;\n height: 1rem;\n pointer-events: none;\n user-select: none;\n background-color: #ddd;\n background-repeat: no-repeat;\n background-position: center center;\n background-size: 50% 50%;\n}\n\n.custom-checkbox .custom-control-indicator {\n border-radius: 0.25rem;\n}\n\n.custom-checkbox .custom-control-input:checked ~ .custom-control-indicator {\n background-image: url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E\");\n}\n\n.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-indicator {\n background-color: #007bff;\n background-image: url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E\");\n}\n\n.custom-radio .custom-control-indicator {\n border-radius: 50%;\n}\n\n.custom-radio .custom-control-input:checked ~ .custom-control-indicator {\n background-image: url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E\");\n}\n\n.custom-controls-stacked {\n display: flex;\n flex-direction: column;\n}\n\n.custom-controls-stacked .custom-control {\n margin-bottom: 0.25rem;\n}\n\n.custom-controls-stacked .custom-control + .custom-control {\n margin-left: 0;\n}\n\n.custom-select {\n display: inline-block;\n max-width: 100%;\n height: calc(2.25rem + 2px);\n padding: 0.375rem 1.75rem 0.375rem 0.75rem;\n line-height: 1.25;\n color: #495057;\n vertical-align: middle;\n background: #fff url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23333' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E\") no-repeat right 0.75rem center;\n background-size: 8px 10px;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 0.25rem;\n appearance: none;\n}\n\n.custom-select:focus {\n border-color: #80bdff;\n outline: none;\n}\n\n.custom-select:focus::-ms-value {\n color: #495057;\n background-color: #fff;\n}\n\n.custom-select:disabled {\n color: #868e96;\n background-color: #e9ecef;\n}\n\n.custom-select::-ms-expand {\n opacity: 0;\n}\n\n.custom-select-sm {\n height: calc(1.8125rem + 2px);\n padding-top: 0.375rem;\n padding-bottom: 0.375rem;\n font-size: 75%;\n}\n\n.custom-file {\n position: relative;\n display: inline-block;\n max-width: 100%;\n height: 2.5rem;\n margin-bottom: 0;\n}\n\n.custom-file-input {\n min-width: 14rem;\n max-width: 100%;\n height: 2.5rem;\n margin: 0;\n opacity: 0;\n}\n\n.custom-file-control {\n position: absolute;\n top: 0;\n right: 0;\n left: 0;\n z-index: 5;\n height: 2.5rem;\n padding: 0.5rem 1rem;\n line-height: 1.5;\n color: #495057;\n pointer-events: none;\n user-select: none;\n background-color: #fff;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 0.25rem;\n}\n\n.custom-file-control:lang(en):empty::after {\n content: \"Choose file...\";\n}\n\n.custom-file-control::before {\n position: absolute;\n top: -1px;\n right: -1px;\n bottom: -1px;\n z-index: 6;\n display: block;\n height: 2.5rem;\n padding: 0.5rem 1rem;\n line-height: 1.5;\n color: #495057;\n background-color: #e9ecef;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 0 0.25rem 0.25rem 0;\n}\n\n.custom-file-control:lang(en)::before {\n content: \"Browse\";\n}\n\n.nav {\n display: flex;\n flex-wrap: wrap;\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n\n.nav-link {\n display: block;\n padding: 0.5rem 1rem;\n}\n\n.nav-link:focus, .nav-link:hover {\n text-decoration: none;\n}\n\n.nav-link.disabled {\n color: #868e96;\n}\n\n.nav-tabs {\n border-bottom: 1px solid #ddd;\n}\n\n.nav-tabs .nav-item {\n margin-bottom: -1px;\n}\n\n.nav-tabs .nav-link {\n border: 1px solid transparent;\n border-top-left-radius: 0.25rem;\n border-top-right-radius: 0.25rem;\n}\n\n.nav-tabs .nav-link:focus, .nav-tabs .nav-link:hover {\n border-color: #e9ecef #e9ecef #ddd;\n}\n\n.nav-tabs .nav-link.disabled {\n color: #868e96;\n background-color: transparent;\n border-color: transparent;\n}\n\n.nav-tabs .nav-link.active,\n.nav-tabs .nav-item.show .nav-link {\n color: #495057;\n background-color: #fff;\n border-color: #ddd #ddd #fff;\n}\n\n.nav-tabs .dropdown-menu {\n margin-top: -1px;\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n\n.nav-pills .nav-link {\n border-radius: 0.25rem;\n}\n\n.nav-pills .nav-link.active,\n.show > .nav-pills .nav-link {\n color: #fff;\n background-color: #007bff;\n}\n\n.nav-fill .nav-item {\n flex: 1 1 auto;\n text-align: center;\n}\n\n.nav-justified .nav-item {\n flex-basis: 0;\n flex-grow: 1;\n text-align: center;\n}\n\n.tab-content > .tab-pane {\n display: none;\n}\n\n.tab-content > .active {\n display: block;\n}\n\n.navbar {\n position: relative;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 1rem;\n}\n\n.navbar > .container,\n.navbar > .container-fluid {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n}\n\n@media (max-width: 575px) {\n .navbar > .container,\n .navbar > .container-fluid {\n width: 100%;\n margin-right: 0;\n margin-left: 0;\n }\n}\n\n.navbar-brand {\n display: inline-block;\n padding-top: 0.3125rem;\n padding-bottom: 0.3125rem;\n margin-right: 1rem;\n font-size: 1.25rem;\n line-height: inherit;\n white-space: nowrap;\n}\n\n.navbar-brand:focus, .navbar-brand:hover {\n text-decoration: none;\n}\n\n.navbar-nav {\n display: flex;\n flex-direction: column;\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n\n.navbar-nav .nav-link {\n padding-right: 0;\n padding-left: 0;\n}\n\n.navbar-nav .dropdown-menu {\n position: static;\n float: none;\n}\n\n.navbar-text {\n display: inline-block;\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n}\n\n.navbar-collapse {\n flex-basis: 100%;\n}\n\n.navbar-toggler {\n padding: 0.25rem 0.75rem;\n font-size: 1.25rem;\n line-height: 1;\n background: transparent;\n border: 1px solid transparent;\n border-radius: 0.25rem;\n}\n\n.navbar-toggler:focus, .navbar-toggler:hover {\n text-decoration: none;\n}\n\n.navbar-toggler-icon {\n display: inline-block;\n width: 1.5em;\n height: 1.5em;\n vertical-align: middle;\n content: \"\";\n background: no-repeat center center;\n background-size: 100% 100%;\n}\n\n@media (max-width: 575px) {\n .navbar-expand-sm > .container,\n .navbar-expand-sm > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n@media (min-width: 576px) {\n .navbar-expand-sm {\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-sm .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-sm .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-sm .navbar-nav .dropdown-menu-right {\n right: 0;\n left: auto;\n }\n .navbar-expand-sm .navbar-nav .nav-link {\n padding-right: .5rem;\n padding-left: .5rem;\n }\n .navbar-expand-sm > .container,\n .navbar-expand-sm > .container-fluid {\n flex-wrap: nowrap;\n }\n .navbar-expand-sm .navbar-collapse {\n display: flex !important;\n }\n .navbar-expand-sm .navbar-toggler {\n display: none;\n }\n}\n\n@media (max-width: 767px) {\n .navbar-expand-md > .container,\n .navbar-expand-md > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n@media (min-width: 768px) {\n .navbar-expand-md {\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-md .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-md .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-md .navbar-nav .dropdown-menu-right {\n right: 0;\n left: auto;\n }\n .navbar-expand-md .navbar-nav .nav-link {\n padding-right: .5rem;\n padding-left: .5rem;\n }\n .navbar-expand-md > .container,\n .navbar-expand-md > .container-fluid {\n flex-wrap: nowrap;\n }\n .navbar-expand-md .navbar-collapse {\n display: flex !important;\n }\n .navbar-expand-md .navbar-toggler {\n display: none;\n }\n}\n\n@media (max-width: 991px) {\n .navbar-expand-lg > .container,\n .navbar-expand-lg > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n@media (min-width: 992px) {\n .navbar-expand-lg {\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-lg .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-lg .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-lg .navbar-nav .dropdown-menu-right {\n right: 0;\n left: auto;\n }\n .navbar-expand-lg .navbar-nav .nav-link {\n padding-right: .5rem;\n padding-left: .5rem;\n }\n .navbar-expand-lg > .container,\n .navbar-expand-lg > .container-fluid {\n flex-wrap: nowrap;\n }\n .navbar-expand-lg .navbar-collapse {\n display: flex !important;\n }\n .navbar-expand-lg .navbar-toggler {\n display: none;\n }\n}\n\n@media (max-width: 1199px) {\n .navbar-expand-xl > .container,\n .navbar-expand-xl > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n@media (min-width: 1200px) {\n .navbar-expand-xl {\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-xl .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-xl .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-xl .navbar-nav .dropdown-menu-right {\n right: 0;\n left: auto;\n }\n .navbar-expand-xl .navbar-nav .nav-link {\n padding-right: .5rem;\n padding-left: .5rem;\n }\n .navbar-expand-xl > .container,\n .navbar-expand-xl > .container-fluid {\n flex-wrap: nowrap;\n }\n .navbar-expand-xl .navbar-collapse {\n display: flex !important;\n }\n .navbar-expand-xl .navbar-toggler {\n display: none;\n }\n}\n\n.navbar-expand {\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n}\n\n.navbar-expand > .container,\n.navbar-expand > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n}\n\n.navbar-expand .navbar-nav {\n flex-direction: row;\n}\n\n.navbar-expand .navbar-nav .dropdown-menu {\n position: absolute;\n}\n\n.navbar-expand .navbar-nav .dropdown-menu-right {\n right: 0;\n left: auto;\n}\n\n.navbar-expand .navbar-nav .nav-link {\n padding-right: .5rem;\n padding-left: .5rem;\n}\n\n.navbar-expand > .container,\n.navbar-expand > .container-fluid {\n flex-wrap: nowrap;\n}\n\n.navbar-expand .navbar-collapse {\n display: flex !important;\n}\n\n.navbar-expand .navbar-toggler {\n display: none;\n}\n\n.navbar-light .navbar-brand {\n color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-light .navbar-brand:focus, .navbar-light .navbar-brand:hover {\n color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-light .navbar-nav .nav-link {\n color: rgba(0, 0, 0, 0.5);\n}\n\n.navbar-light .navbar-nav .nav-link:focus, .navbar-light .navbar-nav .nav-link:hover {\n color: rgba(0, 0, 0, 0.7);\n}\n\n.navbar-light .navbar-nav .nav-link.disabled {\n color: rgba(0, 0, 0, 0.3);\n}\n\n.navbar-light .navbar-nav .show > .nav-link,\n.navbar-light .navbar-nav .active > .nav-link,\n.navbar-light .navbar-nav .nav-link.show,\n.navbar-light .navbar-nav .nav-link.active {\n color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-light .navbar-toggler {\n color: rgba(0, 0, 0, 0.5);\n border-color: rgba(0, 0, 0, 0.1);\n}\n\n.navbar-light .navbar-toggler-icon {\n background-image: url(\"data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E\");\n}\n\n.navbar-light .navbar-text {\n color: rgba(0, 0, 0, 0.5);\n}\n\n.navbar-dark .navbar-brand {\n color: white;\n}\n\n.navbar-dark .navbar-brand:focus, .navbar-dark .navbar-brand:hover {\n color: white;\n}\n\n.navbar-dark .navbar-nav .nav-link {\n color: rgba(255, 255, 255, 0.5);\n}\n\n.navbar-dark .navbar-nav .nav-link:focus, .navbar-dark .navbar-nav .nav-link:hover {\n color: rgba(255, 255, 255, 0.75);\n}\n\n.navbar-dark .navbar-nav .nav-link.disabled {\n color: rgba(255, 255, 255, 0.25);\n}\n\n.navbar-dark .navbar-nav .show > .nav-link,\n.navbar-dark .navbar-nav .active > .nav-link,\n.navbar-dark .navbar-nav .nav-link.show,\n.navbar-dark .navbar-nav .nav-link.active {\n color: white;\n}\n\n.navbar-dark .navbar-toggler {\n color: rgba(255, 255, 255, 0.5);\n border-color: rgba(255, 255, 255, 0.1);\n}\n\n.navbar-dark .navbar-toggler-icon {\n background-image: url(\"data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E\");\n}\n\n.navbar-dark .navbar-text {\n color: rgba(255, 255, 255, 0.5);\n}\n\n.card {\n position: relative;\n display: flex;\n flex-direction: column;\n min-width: 0;\n word-wrap: break-word;\n background-color: #fff;\n background-clip: border-box;\n border: 1px solid rgba(0, 0, 0, 0.125);\n border-radius: 0.25rem;\n}\n\n.card-body {\n flex: 1 1 auto;\n padding: 1.25rem;\n}\n\n.card-title {\n margin-bottom: 0.75rem;\n}\n\n.card-subtitle {\n margin-top: -0.375rem;\n margin-bottom: 0;\n}\n\n.card-text:last-child {\n margin-bottom: 0;\n}\n\n.card-link:hover {\n text-decoration: none;\n}\n\n.card-link + .card-link {\n margin-left: 1.25rem;\n}\n\n.card > .list-group:first-child .list-group-item:first-child {\n border-top-left-radius: 0.25rem;\n border-top-right-radius: 0.25rem;\n}\n\n.card > .list-group:last-child .list-group-item:last-child {\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n}\n\n.card-header {\n padding: 0.75rem 1.25rem;\n margin-bottom: 0;\n background-color: rgba(0, 0, 0, 0.03);\n border-bottom: 1px solid rgba(0, 0, 0, 0.125);\n}\n\n.card-header:first-child {\n border-radius: calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0;\n}\n\n.card-footer {\n padding: 0.75rem 1.25rem;\n background-color: rgba(0, 0, 0, 0.03);\n border-top: 1px solid rgba(0, 0, 0, 0.125);\n}\n\n.card-footer:last-child {\n border-radius: 0 0 calc(0.25rem - 1px) calc(0.25rem - 1px);\n}\n\n.card-header-tabs {\n margin-right: -0.625rem;\n margin-bottom: -0.75rem;\n margin-left: -0.625rem;\n border-bottom: 0;\n}\n\n.card-header-pills {\n margin-right: -0.625rem;\n margin-left: -0.625rem;\n}\n\n.card-img-overlay {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n padding: 1.25rem;\n}\n\n.card-img {\n width: 100%;\n border-radius: calc(0.25rem - 1px);\n}\n\n.card-img-top {\n width: 100%;\n border-top-left-radius: calc(0.25rem - 1px);\n border-top-right-radius: calc(0.25rem - 1px);\n}\n\n.card-img-bottom {\n width: 100%;\n border-bottom-right-radius: calc(0.25rem - 1px);\n border-bottom-left-radius: calc(0.25rem - 1px);\n}\n\n@media (min-width: 576px) {\n .card-deck {\n display: flex;\n flex-flow: row wrap;\n margin-right: -15px;\n margin-left: -15px;\n }\n .card-deck .card {\n display: flex;\n flex: 1 0 0%;\n flex-direction: column;\n margin-right: 15px;\n margin-left: 15px;\n }\n}\n\n@media (min-width: 576px) {\n .card-group {\n display: flex;\n flex-flow: row wrap;\n }\n .card-group .card {\n flex: 1 0 0%;\n }\n .card-group .card + .card {\n margin-left: 0;\n border-left: 0;\n }\n .card-group .card:first-child {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n }\n .card-group .card:first-child .card-img-top {\n border-top-right-radius: 0;\n }\n .card-group .card:first-child .card-img-bottom {\n border-bottom-right-radius: 0;\n }\n .card-group .card:last-child {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n }\n .card-group .card:last-child .card-img-top {\n border-top-left-radius: 0;\n }\n .card-group .card:last-child .card-img-bottom {\n border-bottom-left-radius: 0;\n }\n .card-group .card:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n .card-group .card:not(:first-child):not(:last-child) .card-img-top,\n .card-group .card:not(:first-child):not(:last-child) .card-img-bottom {\n border-radius: 0;\n }\n}\n\n.card-columns .card {\n margin-bottom: 0.75rem;\n}\n\n@media (min-width: 576px) {\n .card-columns {\n column-count: 3;\n column-gap: 1.25rem;\n }\n .card-columns .card {\n display: inline-block;\n width: 100%;\n }\n}\n\n.breadcrumb {\n padding: 0.75rem 1rem;\n margin-bottom: 1rem;\n list-style: none;\n background-color: #e9ecef;\n border-radius: 0.25rem;\n}\n\n.breadcrumb::after {\n display: block;\n clear: both;\n content: \"\";\n}\n\n.breadcrumb-item {\n float: left;\n}\n\n.breadcrumb-item + .breadcrumb-item::before {\n display: inline-block;\n padding-right: 0.5rem;\n padding-left: 0.5rem;\n color: #868e96;\n content: \"/\";\n}\n\n.breadcrumb-item + .breadcrumb-item:hover::before {\n text-decoration: underline;\n}\n\n.breadcrumb-item + .breadcrumb-item:hover::before {\n text-decoration: none;\n}\n\n.breadcrumb-item.active {\n color: #868e96;\n}\n\n.pagination {\n display: flex;\n padding-left: 0;\n list-style: none;\n border-radius: 0.25rem;\n}\n\n.page-item:first-child .page-link {\n margin-left: 0;\n border-top-left-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n}\n\n.page-item:last-child .page-link {\n border-top-right-radius: 0.25rem;\n border-bottom-right-radius: 0.25rem;\n}\n\n.page-item.active .page-link {\n z-index: 2;\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.page-item.disabled .page-link {\n color: #868e96;\n pointer-events: none;\n background-color: #fff;\n border-color: #ddd;\n}\n\n.page-link {\n position: relative;\n display: block;\n padding: 0.5rem 0.75rem;\n margin-left: -1px;\n line-height: 1.25;\n color: #007bff;\n background-color: #fff;\n border: 1px solid #ddd;\n}\n\n.page-link:focus, .page-link:hover {\n color: #0056b3;\n text-decoration: none;\n background-color: #e9ecef;\n border-color: #ddd;\n}\n\n.pagination-lg .page-link {\n padding: 0.75rem 1.5rem;\n font-size: 1.25rem;\n line-height: 1.5;\n}\n\n.pagination-lg .page-item:first-child .page-link {\n border-top-left-radius: 0.3rem;\n border-bottom-left-radius: 0.3rem;\n}\n\n.pagination-lg .page-item:last-child .page-link {\n border-top-right-radius: 0.3rem;\n border-bottom-right-radius: 0.3rem;\n}\n\n.pagination-sm .page-link {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n line-height: 1.5;\n}\n\n.pagination-sm .page-item:first-child .page-link {\n border-top-left-radius: 0.2rem;\n border-bottom-left-radius: 0.2rem;\n}\n\n.pagination-sm .page-item:last-child .page-link {\n border-top-right-radius: 0.2rem;\n border-bottom-right-radius: 0.2rem;\n}\n\n.badge {\n display: inline-block;\n padding: 0.25em 0.4em;\n font-size: 75%;\n font-weight: bold;\n line-height: 1;\n color: #fff;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: 0.25rem;\n}\n\n.badge:empty {\n display: none;\n}\n\n.btn .badge {\n position: relative;\n top: -1px;\n}\n\n.badge-pill {\n padding-right: 0.6em;\n padding-left: 0.6em;\n border-radius: 10rem;\n}\n\n.badge-primary {\n color: #fff;\n background-color: #007bff;\n}\n\n.badge-primary[href]:focus, .badge-primary[href]:hover {\n color: #fff;\n text-decoration: none;\n background-color: #0062cc;\n}\n\n.badge-secondary {\n color: #fff;\n background-color: #868e96;\n}\n\n.badge-secondary[href]:focus, .badge-secondary[href]:hover {\n color: #fff;\n text-decoration: none;\n background-color: #6c757d;\n}\n\n.badge-success {\n color: #fff;\n background-color: #28a745;\n}\n\n.badge-success[href]:focus, .badge-success[href]:hover {\n color: #fff;\n text-decoration: none;\n background-color: #1e7e34;\n}\n\n.badge-info {\n color: #fff;\n background-color: #17a2b8;\n}\n\n.badge-info[href]:focus, .badge-info[href]:hover {\n color: #fff;\n text-decoration: none;\n background-color: #117a8b;\n}\n\n.badge-warning {\n color: #111;\n background-color: #ffc107;\n}\n\n.badge-warning[href]:focus, .badge-warning[href]:hover {\n color: #111;\n text-decoration: none;\n background-color: #d39e00;\n}\n\n.badge-danger {\n color: #fff;\n background-color: #dc3545;\n}\n\n.badge-danger[href]:focus, .badge-danger[href]:hover {\n color: #fff;\n text-decoration: none;\n background-color: #bd2130;\n}\n\n.badge-light {\n color: #111;\n background-color: #f8f9fa;\n}\n\n.badge-light[href]:focus, .badge-light[href]:hover {\n color: #111;\n text-decoration: none;\n background-color: #dae0e5;\n}\n\n.badge-dark {\n color: #fff;\n background-color: #343a40;\n}\n\n.badge-dark[href]:focus, .badge-dark[href]:hover {\n color: #fff;\n text-decoration: none;\n background-color: #1d2124;\n}\n\n.jumbotron {\n padding: 2rem 1rem;\n margin-bottom: 2rem;\n background-color: #e9ecef;\n border-radius: 0.3rem;\n}\n\n@media (min-width: 576px) {\n .jumbotron {\n padding: 4rem 2rem;\n }\n}\n\n.jumbotron-fluid {\n padding-right: 0;\n padding-left: 0;\n border-radius: 0;\n}\n\n.alert {\n padding: 0.75rem 1.25rem;\n margin-bottom: 1rem;\n border: 1px solid transparent;\n border-radius: 0.25rem;\n}\n\n.alert-heading {\n color: inherit;\n}\n\n.alert-link {\n font-weight: bold;\n}\n\n.alert-dismissible .close {\n position: relative;\n top: -0.75rem;\n right: -1.25rem;\n padding: 0.75rem 1.25rem;\n color: inherit;\n}\n\n.alert-primary {\n color: #004085;\n background-color: #cce5ff;\n border-color: #b8daff;\n}\n\n.alert-primary hr {\n border-top-color: #9fcdff;\n}\n\n.alert-primary .alert-link {\n color: #002752;\n}\n\n.alert-secondary {\n color: #464a4e;\n background-color: #e7e8ea;\n border-color: #dddfe2;\n}\n\n.alert-secondary hr {\n border-top-color: #cfd2d6;\n}\n\n.alert-secondary .alert-link {\n color: #2e3133;\n}\n\n.alert-success {\n color: #155724;\n background-color: #d4edda;\n border-color: #c3e6cb;\n}\n\n.alert-success hr {\n border-top-color: #b1dfbb;\n}\n\n.alert-success .alert-link {\n color: #0b2e13;\n}\n\n.alert-info {\n color: #0c5460;\n background-color: #d1ecf1;\n border-color: #bee5eb;\n}\n\n.alert-info hr {\n border-top-color: #abdde5;\n}\n\n.alert-info .alert-link {\n color: #062c33;\n}\n\n.alert-warning {\n color: #856404;\n background-color: #fff3cd;\n border-color: #ffeeba;\n}\n\n.alert-warning hr {\n border-top-color: #ffe8a1;\n}\n\n.alert-warning .alert-link {\n color: #533f03;\n}\n\n.alert-danger {\n color: #721c24;\n background-color: #f8d7da;\n border-color: #f5c6cb;\n}\n\n.alert-danger hr {\n border-top-color: #f1b0b7;\n}\n\n.alert-danger .alert-link {\n color: #491217;\n}\n\n.alert-light {\n color: #818182;\n background-color: #fefefe;\n border-color: #fdfdfe;\n}\n\n.alert-light hr {\n border-top-color: #ececf6;\n}\n\n.alert-light .alert-link {\n color: #686868;\n}\n\n.alert-dark {\n color: #1b1e21;\n background-color: #d6d8d9;\n border-color: #c6c8ca;\n}\n\n.alert-dark hr {\n border-top-color: #b9bbbe;\n}\n\n.alert-dark .alert-link {\n color: #040505;\n}\n\n@keyframes progress-bar-stripes {\n from {\n background-position: 1rem 0;\n }\n to {\n background-position: 0 0;\n }\n}\n\n.progress {\n display: flex;\n overflow: hidden;\n font-size: 0.75rem;\n line-height: 1rem;\n text-align: center;\n background-color: #e9ecef;\n border-radius: 0.25rem;\n}\n\n.progress-bar {\n height: 1rem;\n line-height: 1rem;\n color: #fff;\n background-color: #007bff;\n transition: width 0.6s ease;\n}\n\n.progress-bar-striped {\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-size: 1rem 1rem;\n}\n\n.progress-bar-animated {\n animation: progress-bar-stripes 1s linear infinite;\n}\n\n.media {\n display: flex;\n align-items: flex-start;\n}\n\n.media-body {\n flex: 1;\n}\n\n.list-group {\n display: flex;\n flex-direction: column;\n padding-left: 0;\n margin-bottom: 0;\n}\n\n.list-group-item-action {\n width: 100%;\n color: #495057;\n text-align: inherit;\n}\n\n.list-group-item-action:focus, .list-group-item-action:hover {\n color: #495057;\n text-decoration: none;\n background-color: #f8f9fa;\n}\n\n.list-group-item-action:active {\n color: #212529;\n background-color: #e9ecef;\n}\n\n.list-group-item {\n position: relative;\n display: block;\n padding: 0.75rem 1.25rem;\n margin-bottom: -1px;\n background-color: #fff;\n border: 1px solid rgba(0, 0, 0, 0.125);\n}\n\n.list-group-item:first-child {\n border-top-left-radius: 0.25rem;\n border-top-right-radius: 0.25rem;\n}\n\n.list-group-item:last-child {\n margin-bottom: 0;\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n}\n\n.list-group-item:focus, .list-group-item:hover {\n text-decoration: none;\n}\n\n.list-group-item.disabled, .list-group-item:disabled {\n color: #868e96;\n background-color: #fff;\n}\n\n.list-group-item.active {\n z-index: 2;\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.list-group-flush .list-group-item {\n border-right: 0;\n border-left: 0;\n border-radius: 0;\n}\n\n.list-group-flush:first-child .list-group-item:first-child {\n border-top: 0;\n}\n\n.list-group-flush:last-child .list-group-item:last-child {\n border-bottom: 0;\n}\n\n.list-group-item-primary {\n color: #004085;\n background-color: #b8daff;\n}\n\na.list-group-item-primary,\nbutton.list-group-item-primary {\n color: #004085;\n}\n\na.list-group-item-primary:focus, a.list-group-item-primary:hover,\nbutton.list-group-item-primary:focus,\nbutton.list-group-item-primary:hover {\n color: #004085;\n background-color: #9fcdff;\n}\n\na.list-group-item-primary.active,\nbutton.list-group-item-primary.active {\n color: #fff;\n background-color: #004085;\n border-color: #004085;\n}\n\n.list-group-item-secondary {\n color: #464a4e;\n background-color: #dddfe2;\n}\n\na.list-group-item-secondary,\nbutton.list-group-item-secondary {\n color: #464a4e;\n}\n\na.list-group-item-secondary:focus, a.list-group-item-secondary:hover,\nbutton.list-group-item-secondary:focus,\nbutton.list-group-item-secondary:hover {\n color: #464a4e;\n background-color: #cfd2d6;\n}\n\na.list-group-item-secondary.active,\nbutton.list-group-item-secondary.active {\n color: #fff;\n background-color: #464a4e;\n border-color: #464a4e;\n}\n\n.list-group-item-success {\n color: #155724;\n background-color: #c3e6cb;\n}\n\na.list-group-item-success,\nbutton.list-group-item-success {\n color: #155724;\n}\n\na.list-group-item-success:focus, a.list-group-item-success:hover,\nbutton.list-group-item-success:focus,\nbutton.list-group-item-success:hover {\n color: #155724;\n background-color: #b1dfbb;\n}\n\na.list-group-item-success.active,\nbutton.list-group-item-success.active {\n color: #fff;\n background-color: #155724;\n border-color: #155724;\n}\n\n.list-group-item-info {\n color: #0c5460;\n background-color: #bee5eb;\n}\n\na.list-group-item-info,\nbutton.list-group-item-info {\n color: #0c5460;\n}\n\na.list-group-item-info:focus, a.list-group-item-info:hover,\nbutton.list-group-item-info:focus,\nbutton.list-group-item-info:hover {\n color: #0c5460;\n background-color: #abdde5;\n}\n\na.list-group-item-info.active,\nbutton.list-group-item-info.active {\n color: #fff;\n background-color: #0c5460;\n border-color: #0c5460;\n}\n\n.list-group-item-warning {\n color: #856404;\n background-color: #ffeeba;\n}\n\na.list-group-item-warning,\nbutton.list-group-item-warning {\n color: #856404;\n}\n\na.list-group-item-warning:focus, a.list-group-item-warning:hover,\nbutton.list-group-item-warning:focus,\nbutton.list-group-item-warning:hover {\n color: #856404;\n background-color: #ffe8a1;\n}\n\na.list-group-item-warning.active,\nbutton.list-group-item-warning.active {\n color: #fff;\n background-color: #856404;\n border-color: #856404;\n}\n\n.list-group-item-danger {\n color: #721c24;\n background-color: #f5c6cb;\n}\n\na.list-group-item-danger,\nbutton.list-group-item-danger {\n color: #721c24;\n}\n\na.list-group-item-danger:focus, a.list-group-item-danger:hover,\nbutton.list-group-item-danger:focus,\nbutton.list-group-item-danger:hover {\n color: #721c24;\n background-color: #f1b0b7;\n}\n\na.list-group-item-danger.active,\nbutton.list-group-item-danger.active {\n color: #fff;\n background-color: #721c24;\n border-color: #721c24;\n}\n\n.list-group-item-light {\n color: #818182;\n background-color: #fdfdfe;\n}\n\na.list-group-item-light,\nbutton.list-group-item-light {\n color: #818182;\n}\n\na.list-group-item-light:focus, a.list-group-item-light:hover,\nbutton.list-group-item-light:focus,\nbutton.list-group-item-light:hover {\n color: #818182;\n background-color: #ececf6;\n}\n\na.list-group-item-light.active,\nbutton.list-group-item-light.active {\n color: #fff;\n background-color: #818182;\n border-color: #818182;\n}\n\n.list-group-item-dark {\n color: #1b1e21;\n background-color: #c6c8ca;\n}\n\na.list-group-item-dark,\nbutton.list-group-item-dark {\n color: #1b1e21;\n}\n\na.list-group-item-dark:focus, a.list-group-item-dark:hover,\nbutton.list-group-item-dark:focus,\nbutton.list-group-item-dark:hover {\n color: #1b1e21;\n background-color: #b9bbbe;\n}\n\na.list-group-item-dark.active,\nbutton.list-group-item-dark.active {\n color: #fff;\n background-color: #1b1e21;\n border-color: #1b1e21;\n}\n\n.embed-responsive {\n position: relative;\n display: block;\n width: 100%;\n padding: 0;\n overflow: hidden;\n}\n\n.embed-responsive::before {\n display: block;\n content: \"\";\n}\n\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 100%;\n height: 100%;\n border: 0;\n}\n\n.embed-responsive-21by9::before {\n padding-top: 42.857143%;\n}\n\n.embed-responsive-16by9::before {\n padding-top: 56.25%;\n}\n\n.embed-responsive-4by3::before {\n padding-top: 75%;\n}\n\n.embed-responsive-1by1::before {\n padding-top: 100%;\n}\n\n.close {\n float: right;\n font-size: 1.5rem;\n font-weight: bold;\n line-height: 1;\n color: #000;\n text-shadow: 0 1px 0 #fff;\n opacity: .5;\n}\n\n.close:focus, .close:hover {\n color: #000;\n text-decoration: none;\n opacity: .75;\n}\n\nbutton.close {\n padding: 0;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n}\n\n.modal-open {\n overflow: hidden;\n}\n\n.modal {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1050;\n display: none;\n overflow: hidden;\n outline: 0;\n}\n\n.modal.fade .modal-dialog {\n transition: transform 0.3s ease-out;\n transform: translate(0, -25%);\n}\n\n.modal.show .modal-dialog {\n transform: translate(0, 0);\n}\n\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n\n.modal-content {\n position: relative;\n display: flex;\n flex-direction: column;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 0.3rem;\n outline: 0;\n}\n\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1040;\n background-color: #000;\n}\n\n.modal-backdrop.fade {\n opacity: 0;\n}\n\n.modal-backdrop.show {\n opacity: 0.5;\n}\n\n.modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 15px;\n border-bottom: 1px solid #e9ecef;\n}\n\n.modal-title {\n margin-bottom: 0;\n line-height: 1.5;\n}\n\n.modal-body {\n position: relative;\n flex: 1 1 auto;\n padding: 15px;\n}\n\n.modal-footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n padding: 15px;\n border-top: 1px solid #e9ecef;\n}\n\n.modal-footer > :not(:first-child) {\n margin-left: .25rem;\n}\n\n.modal-footer > :not(:last-child) {\n margin-right: .25rem;\n}\n\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n\n@media (min-width: 576px) {\n .modal-dialog {\n max-width: 500px;\n margin: 30px auto;\n }\n .modal-sm {\n max-width: 300px;\n }\n}\n\n@media (min-width: 992px) {\n .modal-lg {\n max-width: 800px;\n }\n}\n\n.tooltip {\n position: absolute;\n z-index: 1070;\n display: block;\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n font-style: normal;\n font-weight: normal;\n line-height: 1.5;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n white-space: normal;\n line-break: auto;\n font-size: 0.875rem;\n word-wrap: break-word;\n opacity: 0;\n}\n\n.tooltip.show {\n opacity: 0.9;\n}\n\n.tooltip .arrow {\n position: absolute;\n display: block;\n width: 5px;\n height: 5px;\n}\n\n.tooltip.bs-tooltip-top, .tooltip.bs-tooltip-auto[x-placement^=\"top\"] {\n padding: 5px 0;\n}\n\n.tooltip.bs-tooltip-top .arrow, .tooltip.bs-tooltip-auto[x-placement^=\"top\"] .arrow {\n bottom: 0;\n}\n\n.tooltip.bs-tooltip-top .arrow::before, .tooltip.bs-tooltip-auto[x-placement^=\"top\"] .arrow::before {\n margin-left: -3px;\n content: \"\";\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n\n.tooltip.bs-tooltip-right, .tooltip.bs-tooltip-auto[x-placement^=\"right\"] {\n padding: 0 5px;\n}\n\n.tooltip.bs-tooltip-right .arrow, .tooltip.bs-tooltip-auto[x-placement^=\"right\"] .arrow {\n left: 0;\n}\n\n.tooltip.bs-tooltip-right .arrow::before, .tooltip.bs-tooltip-auto[x-placement^=\"right\"] .arrow::before {\n margin-top: -3px;\n content: \"\";\n border-width: 5px 5px 5px 0;\n border-right-color: #000;\n}\n\n.tooltip.bs-tooltip-bottom, .tooltip.bs-tooltip-auto[x-placement^=\"bottom\"] {\n padding: 5px 0;\n}\n\n.tooltip.bs-tooltip-bottom .arrow, .tooltip.bs-tooltip-auto[x-placement^=\"bottom\"] .arrow {\n top: 0;\n}\n\n.tooltip.bs-tooltip-bottom .arrow::before, .tooltip.bs-tooltip-auto[x-placement^=\"bottom\"] .arrow::before {\n margin-left: -3px;\n content: \"\";\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n\n.tooltip.bs-tooltip-left, .tooltip.bs-tooltip-auto[x-placement^=\"left\"] {\n padding: 0 5px;\n}\n\n.tooltip.bs-tooltip-left .arrow, .tooltip.bs-tooltip-auto[x-placement^=\"left\"] .arrow {\n right: 0;\n}\n\n.tooltip.bs-tooltip-left .arrow::before, .tooltip.bs-tooltip-auto[x-placement^=\"left\"] .arrow::before {\n right: 0;\n margin-top: -3px;\n content: \"\";\n border-width: 5px 0 5px 5px;\n border-left-color: #000;\n}\n\n.tooltip .arrow::before {\n position: absolute;\n border-color: transparent;\n border-style: solid;\n}\n\n.tooltip-inner {\n max-width: 200px;\n padding: 3px 8px;\n color: #fff;\n text-align: center;\n background-color: #000;\n border-radius: 0.25rem;\n}\n\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1060;\n display: block;\n max-width: 276px;\n padding: 1px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n font-style: normal;\n font-weight: normal;\n line-height: 1.5;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n white-space: normal;\n line-break: auto;\n font-size: 0.875rem;\n word-wrap: break-word;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 0.3rem;\n}\n\n.popover .arrow {\n position: absolute;\n display: block;\n width: 10px;\n height: 5px;\n}\n\n.popover .arrow::before,\n.popover .arrow::after {\n position: absolute;\n display: block;\n border-color: transparent;\n border-style: solid;\n}\n\n.popover .arrow::before {\n content: \"\";\n border-width: 11px;\n}\n\n.popover .arrow::after {\n content: \"\";\n border-width: 11px;\n}\n\n.popover.bs-popover-top, .popover.bs-popover-auto[x-placement^=\"top\"] {\n margin-bottom: 10px;\n}\n\n.popover.bs-popover-top .arrow, .popover.bs-popover-auto[x-placement^=\"top\"] .arrow {\n bottom: 0;\n}\n\n.popover.bs-popover-top .arrow::before, .popover.bs-popover-auto[x-placement^=\"top\"] .arrow::before,\n.popover.bs-popover-top .arrow::after, .popover.bs-popover-auto[x-placement^=\"top\"] .arrow::after {\n border-bottom-width: 0;\n}\n\n.popover.bs-popover-top .arrow::before, .popover.bs-popover-auto[x-placement^=\"top\"] .arrow::before {\n bottom: -11px;\n margin-left: -6px;\n border-top-color: rgba(0, 0, 0, 0.25);\n}\n\n.popover.bs-popover-top .arrow::after, .popover.bs-popover-auto[x-placement^=\"top\"] .arrow::after {\n bottom: -10px;\n margin-left: -6px;\n border-top-color: #fff;\n}\n\n.popover.bs-popover-right, .popover.bs-popover-auto[x-placement^=\"right\"] {\n margin-left: 10px;\n}\n\n.popover.bs-popover-right .arrow, .popover.bs-popover-auto[x-placement^=\"right\"] .arrow {\n left: 0;\n}\n\n.popover.bs-popover-right .arrow::before, .popover.bs-popover-auto[x-placement^=\"right\"] .arrow::before,\n.popover.bs-popover-right .arrow::after, .popover.bs-popover-auto[x-placement^=\"right\"] .arrow::after {\n margin-top: -8px;\n border-left-width: 0;\n}\n\n.popover.bs-popover-right .arrow::before, .popover.bs-popover-auto[x-placement^=\"right\"] .arrow::before {\n left: -11px;\n border-right-color: rgba(0, 0, 0, 0.25);\n}\n\n.popover.bs-popover-right .arrow::after, .popover.bs-popover-auto[x-placement^=\"right\"] .arrow::after {\n left: -10px;\n border-right-color: #fff;\n}\n\n.popover.bs-popover-bottom, .popover.bs-popover-auto[x-placement^=\"bottom\"] {\n margin-top: 10px;\n}\n\n.popover.bs-popover-bottom .arrow, .popover.bs-popover-auto[x-placement^=\"bottom\"] .arrow {\n top: 0;\n}\n\n.popover.bs-popover-bottom .arrow::before, .popover.bs-popover-auto[x-placement^=\"bottom\"] .arrow::before,\n.popover.bs-popover-bottom .arrow::after, .popover.bs-popover-auto[x-placement^=\"bottom\"] .arrow::after {\n margin-left: -7px;\n border-top-width: 0;\n}\n\n.popover.bs-popover-bottom .arrow::before, .popover.bs-popover-auto[x-placement^=\"bottom\"] .arrow::before {\n top: -11px;\n border-bottom-color: rgba(0, 0, 0, 0.25);\n}\n\n.popover.bs-popover-bottom .arrow::after, .popover.bs-popover-auto[x-placement^=\"bottom\"] .arrow::after {\n top: -10px;\n border-bottom-color: #fff;\n}\n\n.popover.bs-popover-bottom .popover-header::before, .popover.bs-popover-auto[x-placement^=\"bottom\"] .popover-header::before {\n position: absolute;\n top: 0;\n left: 50%;\n display: block;\n width: 20px;\n margin-left: -10px;\n content: \"\";\n border-bottom: 1px solid #f7f7f7;\n}\n\n.popover.bs-popover-left, .popover.bs-popover-auto[x-placement^=\"left\"] {\n margin-right: 10px;\n}\n\n.popover.bs-popover-left .arrow, .popover.bs-popover-auto[x-placement^=\"left\"] .arrow {\n right: 0;\n}\n\n.popover.bs-popover-left .arrow::before, .popover.bs-popover-auto[x-placement^=\"left\"] .arrow::before,\n.popover.bs-popover-left .arrow::after, .popover.bs-popover-auto[x-placement^=\"left\"] .arrow::after {\n margin-top: -8px;\n border-right-width: 0;\n}\n\n.popover.bs-popover-left .arrow::before, .popover.bs-popover-auto[x-placement^=\"left\"] .arrow::before {\n right: -11px;\n border-left-color: rgba(0, 0, 0, 0.25);\n}\n\n.popover.bs-popover-left .arrow::after, .popover.bs-popover-auto[x-placement^=\"left\"] .arrow::after {\n right: -10px;\n border-left-color: #fff;\n}\n\n.popover-header {\n padding: 8px 14px;\n margin-bottom: 0;\n font-size: 1rem;\n color: inherit;\n background-color: #f7f7f7;\n border-bottom: 1px solid #ebebeb;\n border-top-left-radius: calc(0.3rem - 1px);\n border-top-right-radius: calc(0.3rem - 1px);\n}\n\n.popover-header:empty {\n display: none;\n}\n\n.popover-body {\n padding: 9px 14px;\n color: #212529;\n}\n\n.carousel {\n position: relative;\n}\n\n.carousel-inner {\n position: relative;\n width: 100%;\n overflow: hidden;\n}\n\n.carousel-item {\n position: relative;\n display: none;\n align-items: center;\n width: 100%;\n transition: transform 0.6s ease;\n backface-visibility: hidden;\n perspective: 1000px;\n}\n\n.carousel-item.active,\n.carousel-item-next,\n.carousel-item-prev {\n display: block;\n}\n\n.carousel-item-next,\n.carousel-item-prev {\n position: absolute;\n top: 0;\n}\n\n.carousel-item-next.carousel-item-left,\n.carousel-item-prev.carousel-item-right {\n transform: translateX(0);\n}\n\n@supports (transform-style: preserve-3d) {\n .carousel-item-next.carousel-item-left,\n .carousel-item-prev.carousel-item-right {\n transform: translate3d(0, 0, 0);\n }\n}\n\n.carousel-item-next,\n.active.carousel-item-right {\n transform: translateX(100%);\n}\n\n@supports (transform-style: preserve-3d) {\n .carousel-item-next,\n .active.carousel-item-right {\n transform: translate3d(100%, 0, 0);\n }\n}\n\n.carousel-item-prev,\n.active.carousel-item-left {\n transform: translateX(-100%);\n}\n\n@supports (transform-style: preserve-3d) {\n .carousel-item-prev,\n .active.carousel-item-left {\n transform: translate3d(-100%, 0, 0);\n }\n}\n\n.carousel-control-prev,\n.carousel-control-next {\n position: absolute;\n top: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 15%;\n color: #fff;\n text-align: center;\n opacity: 0.5;\n}\n\n.carousel-control-prev:focus, .carousel-control-prev:hover,\n.carousel-control-next:focus,\n.carousel-control-next:hover {\n color: #fff;\n text-decoration: none;\n outline: 0;\n opacity: .9;\n}\n\n.carousel-control-prev {\n left: 0;\n}\n\n.carousel-control-next {\n right: 0;\n}\n\n.carousel-control-prev-icon,\n.carousel-control-next-icon {\n display: inline-block;\n width: 20px;\n height: 20px;\n background: transparent no-repeat center center;\n background-size: 100% 100%;\n}\n\n.carousel-control-prev-icon {\n background-image: url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M4 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E\");\n}\n\n.carousel-control-next-icon {\n background-image: url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M1.5 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E\");\n}\n\n.carousel-indicators {\n position: absolute;\n right: 0;\n bottom: 10px;\n left: 0;\n z-index: 15;\n display: flex;\n justify-content: center;\n padding-left: 0;\n margin-right: 15%;\n margin-left: 15%;\n list-style: none;\n}\n\n.carousel-indicators li {\n position: relative;\n flex: 0 1 auto;\n width: 30px;\n height: 3px;\n margin-right: 3px;\n margin-left: 3px;\n text-indent: -999px;\n background-color: rgba(255, 255, 255, 0.5);\n}\n\n.carousel-indicators li::before {\n position: absolute;\n top: -10px;\n left: 0;\n display: inline-block;\n width: 100%;\n height: 10px;\n content: \"\";\n}\n\n.carousel-indicators li::after {\n position: absolute;\n bottom: -10px;\n left: 0;\n display: inline-block;\n width: 100%;\n height: 10px;\n content: \"\";\n}\n\n.carousel-indicators .active {\n background-color: #fff;\n}\n\n.carousel-caption {\n position: absolute;\n right: 15%;\n bottom: 20px;\n left: 15%;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: #fff;\n text-align: center;\n}\n\n.align-baseline {\n vertical-align: baseline !important;\n}\n\n.align-top {\n vertical-align: top !important;\n}\n\n.align-middle {\n vertical-align: middle !important;\n}\n\n.align-bottom {\n vertical-align: bottom !important;\n}\n\n.align-text-bottom {\n vertical-align: text-bottom !important;\n}\n\n.align-text-top {\n vertical-align: text-top !important;\n}\n\n.bg-primary {\n background-color: #007bff !important;\n}\n\na.bg-primary:focus, a.bg-primary:hover {\n background-color: #0062cc !important;\n}\n\n.bg-secondary {\n background-color: #868e96 !important;\n}\n\na.bg-secondary:focus, a.bg-secondary:hover {\n background-color: #6c757d !important;\n}\n\n.bg-success {\n background-color: #28a745 !important;\n}\n\na.bg-success:focus, a.bg-success:hover {\n background-color: #1e7e34 !important;\n}\n\n.bg-info {\n background-color: #17a2b8 !important;\n}\n\na.bg-info:focus, a.bg-info:hover {\n background-color: #117a8b !important;\n}\n\n.bg-warning {\n background-color: #ffc107 !important;\n}\n\na.bg-warning:focus, a.bg-warning:hover {\n background-color: #d39e00 !important;\n}\n\n.bg-danger {\n background-color: #dc3545 !important;\n}\n\na.bg-danger:focus, a.bg-danger:hover {\n background-color: #bd2130 !important;\n}\n\n.bg-light {\n background-color: #f8f9fa !important;\n}\n\na.bg-light:focus, a.bg-light:hover {\n background-color: #dae0e5 !important;\n}\n\n.bg-dark {\n background-color: #343a40 !important;\n}\n\na.bg-dark:focus, a.bg-dark:hover {\n background-color: #1d2124 !important;\n}\n\n.bg-transparent {\n background-color: transparent !important;\n}\n\n.border {\n border: 1px solid #e9ecef !important;\n}\n\n.border-0 {\n border: 0 !important;\n}\n\n.border-top-0 {\n border-top: 0 !important;\n}\n\n.border-right-0 {\n border-right: 0 !important;\n}\n\n.border-bottom-0 {\n border-bottom: 0 !important;\n}\n\n.border-left-0 {\n border-left: 0 !important;\n}\n\n.border-primary {\n border-color: #007bff !important;\n}\n\n.border-secondary {\n border-color: #868e96 !important;\n}\n\n.border-success {\n border-color: #28a745 !important;\n}\n\n.border-info {\n border-color: #17a2b8 !important;\n}\n\n.border-warning {\n border-color: #ffc107 !important;\n}\n\n.border-danger {\n border-color: #dc3545 !important;\n}\n\n.border-light {\n border-color: #f8f9fa !important;\n}\n\n.border-dark {\n border-color: #343a40 !important;\n}\n\n.rounded {\n border-radius: 0.25rem !important;\n}\n\n.rounded-top {\n border-top-left-radius: 0.25rem !important;\n border-top-right-radius: 0.25rem !important;\n}\n\n.rounded-right {\n border-top-right-radius: 0.25rem !important;\n border-bottom-right-radius: 0.25rem !important;\n}\n\n.rounded-bottom {\n border-bottom-right-radius: 0.25rem !important;\n border-bottom-left-radius: 0.25rem !important;\n}\n\n.rounded-left {\n border-top-left-radius: 0.25rem !important;\n border-bottom-left-radius: 0.25rem !important;\n}\n\n.rounded-circle {\n border-radius: 50%;\n}\n\n.rounded-0 {\n border-radius: 0;\n}\n\n.clearfix::after {\n display: block;\n clear: both;\n content: \"\";\n}\n\n.d-none {\n display: none !important;\n}\n\n.d-inline {\n display: inline !important;\n}\n\n.d-inline-block {\n display: inline-block !important;\n}\n\n.d-block {\n display: block !important;\n}\n\n.d-table {\n display: table !important;\n}\n\n.d-table-cell {\n display: table-cell !important;\n}\n\n.d-flex {\n display: flex !important;\n}\n\n.d-inline-flex {\n display: inline-flex !important;\n}\n\n@media (min-width: 576px) {\n .d-sm-none {\n display: none !important;\n }\n .d-sm-inline {\n display: inline !important;\n }\n .d-sm-inline-block {\n display: inline-block !important;\n }\n .d-sm-block {\n display: block !important;\n }\n .d-sm-table {\n display: table !important;\n }\n .d-sm-table-cell {\n display: table-cell !important;\n }\n .d-sm-flex {\n display: flex !important;\n }\n .d-sm-inline-flex {\n display: inline-flex !important;\n }\n}\n\n@media (min-width: 768px) {\n .d-md-none {\n display: none !important;\n }\n .d-md-inline {\n display: inline !important;\n }\n .d-md-inline-block {\n display: inline-block !important;\n }\n .d-md-block {\n display: block !important;\n }\n .d-md-table {\n display: table !important;\n }\n .d-md-table-cell {\n display: table-cell !important;\n }\n .d-md-flex {\n display: flex !important;\n }\n .d-md-inline-flex {\n display: inline-flex !important;\n }\n}\n\n@media (min-width: 992px) {\n .d-lg-none {\n display: none !important;\n }\n .d-lg-inline {\n display: inline !important;\n }\n .d-lg-inline-block {\n display: inline-block !important;\n }\n .d-lg-block {\n display: block !important;\n }\n .d-lg-table {\n display: table !important;\n }\n .d-lg-table-cell {\n display: table-cell !important;\n }\n .d-lg-flex {\n display: flex !important;\n }\n .d-lg-inline-flex {\n display: inline-flex !important;\n }\n}\n\n@media (min-width: 1200px) {\n .d-xl-none {\n display: none !important;\n }\n .d-xl-inline {\n display: inline !important;\n }\n .d-xl-inline-block {\n display: inline-block !important;\n }\n .d-xl-block {\n display: block !important;\n }\n .d-xl-table {\n display: table !important;\n }\n .d-xl-table-cell {\n display: table-cell !important;\n }\n .d-xl-flex {\n display: flex !important;\n }\n .d-xl-inline-flex {\n display: inline-flex !important;\n }\n}\n\n.d-print-block {\n display: none !important;\n}\n\n@media print {\n .d-print-block {\n display: block !important;\n }\n}\n\n.d-print-inline {\n display: none !important;\n}\n\n@media print {\n .d-print-inline {\n display: inline !important;\n }\n}\n\n.d-print-inline-block {\n display: none !important;\n}\n\n@media print {\n .d-print-inline-block {\n display: inline-block !important;\n }\n}\n\n@media print {\n .d-print-none {\n display: none !important;\n }\n}\n\n.flex-row {\n flex-direction: row !important;\n}\n\n.flex-column {\n flex-direction: column !important;\n}\n\n.flex-row-reverse {\n flex-direction: row-reverse !important;\n}\n\n.flex-column-reverse {\n flex-direction: column-reverse !important;\n}\n\n.flex-wrap {\n flex-wrap: wrap !important;\n}\n\n.flex-nowrap {\n flex-wrap: nowrap !important;\n}\n\n.flex-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n}\n\n.justify-content-start {\n justify-content: flex-start !important;\n}\n\n.justify-content-end {\n justify-content: flex-end !important;\n}\n\n.justify-content-center {\n justify-content: center !important;\n}\n\n.justify-content-between {\n justify-content: space-between !important;\n}\n\n.justify-content-around {\n justify-content: space-around !important;\n}\n\n.align-items-start {\n align-items: flex-start !important;\n}\n\n.align-items-end {\n align-items: flex-end !important;\n}\n\n.align-items-center {\n align-items: center !important;\n}\n\n.align-items-baseline {\n align-items: baseline !important;\n}\n\n.align-items-stretch {\n align-items: stretch !important;\n}\n\n.align-content-start {\n align-content: flex-start !important;\n}\n\n.align-content-end {\n align-content: flex-end !important;\n}\n\n.align-content-center {\n align-content: center !important;\n}\n\n.align-content-between {\n align-content: space-between !important;\n}\n\n.align-content-around {\n align-content: space-around !important;\n}\n\n.align-content-stretch {\n align-content: stretch !important;\n}\n\n.align-self-auto {\n align-self: auto !important;\n}\n\n.align-self-start {\n align-self: flex-start !important;\n}\n\n.align-self-end {\n align-self: flex-end !important;\n}\n\n.align-self-center {\n align-self: center !important;\n}\n\n.align-self-baseline {\n align-self: baseline !important;\n}\n\n.align-self-stretch {\n align-self: stretch !important;\n}\n\n@media (min-width: 576px) {\n .flex-sm-row {\n flex-direction: row !important;\n }\n .flex-sm-column {\n flex-direction: column !important;\n }\n .flex-sm-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-sm-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-sm-wrap {\n flex-wrap: wrap !important;\n }\n .flex-sm-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-sm-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-sm-start {\n justify-content: flex-start !important;\n }\n .justify-content-sm-end {\n justify-content: flex-end !important;\n }\n .justify-content-sm-center {\n justify-content: center !important;\n }\n .justify-content-sm-between {\n justify-content: space-between !important;\n }\n .justify-content-sm-around {\n justify-content: space-around !important;\n }\n .align-items-sm-start {\n align-items: flex-start !important;\n }\n .align-items-sm-end {\n align-items: flex-end !important;\n }\n .align-items-sm-center {\n align-items: center !important;\n }\n .align-items-sm-baseline {\n align-items: baseline !important;\n }\n .align-items-sm-stretch {\n align-items: stretch !important;\n }\n .align-content-sm-start {\n align-content: flex-start !important;\n }\n .align-content-sm-end {\n align-content: flex-end !important;\n }\n .align-content-sm-center {\n align-content: center !important;\n }\n .align-content-sm-between {\n align-content: space-between !important;\n }\n .align-content-sm-around {\n align-content: space-around !important;\n }\n .align-content-sm-stretch {\n align-content: stretch !important;\n }\n .align-self-sm-auto {\n align-self: auto !important;\n }\n .align-self-sm-start {\n align-self: flex-start !important;\n }\n .align-self-sm-end {\n align-self: flex-end !important;\n }\n .align-self-sm-center {\n align-self: center !important;\n }\n .align-self-sm-baseline {\n align-self: baseline !important;\n }\n .align-self-sm-stretch {\n align-self: stretch !important;\n }\n}\n\n@media (min-width: 768px) {\n .flex-md-row {\n flex-direction: row !important;\n }\n .flex-md-column {\n flex-direction: column !important;\n }\n .flex-md-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-md-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-md-wrap {\n flex-wrap: wrap !important;\n }\n .flex-md-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-md-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-md-start {\n justify-content: flex-start !important;\n }\n .justify-content-md-end {\n justify-content: flex-end !important;\n }\n .justify-content-md-center {\n justify-content: center !important;\n }\n .justify-content-md-between {\n justify-content: space-between !important;\n }\n .justify-content-md-around {\n justify-content: space-around !important;\n }\n .align-items-md-start {\n align-items: flex-start !important;\n }\n .align-items-md-end {\n align-items: flex-end !important;\n }\n .align-items-md-center {\n align-items: center !important;\n }\n .align-items-md-baseline {\n align-items: baseline !important;\n }\n .align-items-md-stretch {\n align-items: stretch !important;\n }\n .align-content-md-start {\n align-content: flex-start !important;\n }\n .align-content-md-end {\n align-content: flex-end !important;\n }\n .align-content-md-center {\n align-content: center !important;\n }\n .align-content-md-between {\n align-content: space-between !important;\n }\n .align-content-md-around {\n align-content: space-around !important;\n }\n .align-content-md-stretch {\n align-content: stretch !important;\n }\n .align-self-md-auto {\n align-self: auto !important;\n }\n .align-self-md-start {\n align-self: flex-start !important;\n }\n .align-self-md-end {\n align-self: flex-end !important;\n }\n .align-self-md-center {\n align-self: center !important;\n }\n .align-self-md-baseline {\n align-self: baseline !important;\n }\n .align-self-md-stretch {\n align-self: stretch !important;\n }\n}\n\n@media (min-width: 992px) {\n .flex-lg-row {\n flex-direction: row !important;\n }\n .flex-lg-column {\n flex-direction: column !important;\n }\n .flex-lg-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-lg-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-lg-wrap {\n flex-wrap: wrap !important;\n }\n .flex-lg-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-lg-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-lg-start {\n justify-content: flex-start !important;\n }\n .justify-content-lg-end {\n justify-content: flex-end !important;\n }\n .justify-content-lg-center {\n justify-content: center !important;\n }\n .justify-content-lg-between {\n justify-content: space-between !important;\n }\n .justify-content-lg-around {\n justify-content: space-around !important;\n }\n .align-items-lg-start {\n align-items: flex-start !important;\n }\n .align-items-lg-end {\n align-items: flex-end !important;\n }\n .align-items-lg-center {\n align-items: center !important;\n }\n .align-items-lg-baseline {\n align-items: baseline !important;\n }\n .align-items-lg-stretch {\n align-items: stretch !important;\n }\n .align-content-lg-start {\n align-content: flex-start !important;\n }\n .align-content-lg-end {\n align-content: flex-end !important;\n }\n .align-content-lg-center {\n align-content: center !important;\n }\n .align-content-lg-between {\n align-content: space-between !important;\n }\n .align-content-lg-around {\n align-content: space-around !important;\n }\n .align-content-lg-stretch {\n align-content: stretch !important;\n }\n .align-self-lg-auto {\n align-self: auto !important;\n }\n .align-self-lg-start {\n align-self: flex-start !important;\n }\n .align-self-lg-end {\n align-self: flex-end !important;\n }\n .align-self-lg-center {\n align-self: center !important;\n }\n .align-self-lg-baseline {\n align-self: baseline !important;\n }\n .align-self-lg-stretch {\n align-self: stretch !important;\n }\n}\n\n@media (min-width: 1200px) {\n .flex-xl-row {\n flex-direction: row !important;\n }\n .flex-xl-column {\n flex-direction: column !important;\n }\n .flex-xl-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-xl-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-xl-wrap {\n flex-wrap: wrap !important;\n }\n .flex-xl-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-xl-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-xl-start {\n justify-content: flex-start !important;\n }\n .justify-content-xl-end {\n justify-content: flex-end !important;\n }\n .justify-content-xl-center {\n justify-content: center !important;\n }\n .justify-content-xl-between {\n justify-content: space-between !important;\n }\n .justify-content-xl-around {\n justify-content: space-around !important;\n }\n .align-items-xl-start {\n align-items: flex-start !important;\n }\n .align-items-xl-end {\n align-items: flex-end !important;\n }\n .align-items-xl-center {\n align-items: center !important;\n }\n .align-items-xl-baseline {\n align-items: baseline !important;\n }\n .align-items-xl-stretch {\n align-items: stretch !important;\n }\n .align-content-xl-start {\n align-content: flex-start !important;\n }\n .align-content-xl-end {\n align-content: flex-end !important;\n }\n .align-content-xl-center {\n align-content: center !important;\n }\n .align-content-xl-between {\n align-content: space-between !important;\n }\n .align-content-xl-around {\n align-content: space-around !important;\n }\n .align-content-xl-stretch {\n align-content: stretch !important;\n }\n .align-self-xl-auto {\n align-self: auto !important;\n }\n .align-self-xl-start {\n align-self: flex-start !important;\n }\n .align-self-xl-end {\n align-self: flex-end !important;\n }\n .align-self-xl-center {\n align-self: center !important;\n }\n .align-self-xl-baseline {\n align-self: baseline !important;\n }\n .align-self-xl-stretch {\n align-self: stretch !important;\n }\n}\n\n.float-left {\n float: left !important;\n}\n\n.float-right {\n float: right !important;\n}\n\n.float-none {\n float: none !important;\n}\n\n@media (min-width: 576px) {\n .float-sm-left {\n float: left !important;\n }\n .float-sm-right {\n float: right !important;\n }\n .float-sm-none {\n float: none !important;\n }\n}\n\n@media (min-width: 768px) {\n .float-md-left {\n float: left !important;\n }\n .float-md-right {\n float: right !important;\n }\n .float-md-none {\n float: none !important;\n }\n}\n\n@media (min-width: 992px) {\n .float-lg-left {\n float: left !important;\n }\n .float-lg-right {\n float: right !important;\n }\n .float-lg-none {\n float: none !important;\n }\n}\n\n@media (min-width: 1200px) {\n .float-xl-left {\n float: left !important;\n }\n .float-xl-right {\n float: right !important;\n }\n .float-xl-none {\n float: none !important;\n }\n}\n\n.fixed-top {\n position: fixed;\n top: 0;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n\n.fixed-bottom {\n position: fixed;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1030;\n}\n\n@supports (position: sticky) {\n .sticky-top {\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n}\n\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n clip-path: inset(50%);\n border: 0;\n}\n\n.sr-only-focusable:active, .sr-only-focusable:focus {\n position: static;\n width: auto;\n height: auto;\n overflow: visible;\n clip: auto;\n white-space: normal;\n clip-path: none;\n}\n\n.w-25 {\n width: 25% !important;\n}\n\n.w-50 {\n width: 50% !important;\n}\n\n.w-75 {\n width: 75% !important;\n}\n\n.w-100 {\n width: 100% !important;\n}\n\n.h-25 {\n height: 25% !important;\n}\n\n.h-50 {\n height: 50% !important;\n}\n\n.h-75 {\n height: 75% !important;\n}\n\n.h-100 {\n height: 100% !important;\n}\n\n.mw-100 {\n max-width: 100% !important;\n}\n\n.mh-100 {\n max-height: 100% !important;\n}\n\n.m-0 {\n margin: 0 !important;\n}\n\n.mt-0 {\n margin-top: 0 !important;\n}\n\n.mr-0 {\n margin-right: 0 !important;\n}\n\n.mb-0 {\n margin-bottom: 0 !important;\n}\n\n.ml-0 {\n margin-left: 0 !important;\n}\n\n.mx-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n}\n\n.my-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n.m-1 {\n margin: 0.25rem !important;\n}\n\n.mt-1 {\n margin-top: 0.25rem !important;\n}\n\n.mr-1 {\n margin-right: 0.25rem !important;\n}\n\n.mb-1 {\n margin-bottom: 0.25rem !important;\n}\n\n.ml-1 {\n margin-left: 0.25rem !important;\n}\n\n.mx-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n}\n\n.my-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n}\n\n.m-2 {\n margin: 0.5rem !important;\n}\n\n.mt-2 {\n margin-top: 0.5rem !important;\n}\n\n.mr-2 {\n margin-right: 0.5rem !important;\n}\n\n.mb-2 {\n margin-bottom: 0.5rem !important;\n}\n\n.ml-2 {\n margin-left: 0.5rem !important;\n}\n\n.mx-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n}\n\n.my-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n}\n\n.m-3 {\n margin: 1rem !important;\n}\n\n.mt-3 {\n margin-top: 1rem !important;\n}\n\n.mr-3 {\n margin-right: 1rem !important;\n}\n\n.mb-3 {\n margin-bottom: 1rem !important;\n}\n\n.ml-3 {\n margin-left: 1rem !important;\n}\n\n.mx-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n}\n\n.my-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n}\n\n.m-4 {\n margin: 1.5rem !important;\n}\n\n.mt-4 {\n margin-top: 1.5rem !important;\n}\n\n.mr-4 {\n margin-right: 1.5rem !important;\n}\n\n.mb-4 {\n margin-bottom: 1.5rem !important;\n}\n\n.ml-4 {\n margin-left: 1.5rem !important;\n}\n\n.mx-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n}\n\n.my-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n}\n\n.m-5 {\n margin: 3rem !important;\n}\n\n.mt-5 {\n margin-top: 3rem !important;\n}\n\n.mr-5 {\n margin-right: 3rem !important;\n}\n\n.mb-5 {\n margin-bottom: 3rem !important;\n}\n\n.ml-5 {\n margin-left: 3rem !important;\n}\n\n.mx-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n}\n\n.my-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n}\n\n.p-0 {\n padding: 0 !important;\n}\n\n.pt-0 {\n padding-top: 0 !important;\n}\n\n.pr-0 {\n padding-right: 0 !important;\n}\n\n.pb-0 {\n padding-bottom: 0 !important;\n}\n\n.pl-0 {\n padding-left: 0 !important;\n}\n\n.px-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n}\n\n.py-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n}\n\n.p-1 {\n padding: 0.25rem !important;\n}\n\n.pt-1 {\n padding-top: 0.25rem !important;\n}\n\n.pr-1 {\n padding-right: 0.25rem !important;\n}\n\n.pb-1 {\n padding-bottom: 0.25rem !important;\n}\n\n.pl-1 {\n padding-left: 0.25rem !important;\n}\n\n.px-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n}\n\n.py-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n}\n\n.p-2 {\n padding: 0.5rem !important;\n}\n\n.pt-2 {\n padding-top: 0.5rem !important;\n}\n\n.pr-2 {\n padding-right: 0.5rem !important;\n}\n\n.pb-2 {\n padding-bottom: 0.5rem !important;\n}\n\n.pl-2 {\n padding-left: 0.5rem !important;\n}\n\n.px-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n}\n\n.py-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n}\n\n.p-3 {\n padding: 1rem !important;\n}\n\n.pt-3 {\n padding-top: 1rem !important;\n}\n\n.pr-3 {\n padding-right: 1rem !important;\n}\n\n.pb-3 {\n padding-bottom: 1rem !important;\n}\n\n.pl-3 {\n padding-left: 1rem !important;\n}\n\n.px-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n}\n\n.py-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n}\n\n.p-4 {\n padding: 1.5rem !important;\n}\n\n.pt-4 {\n padding-top: 1.5rem !important;\n}\n\n.pr-4 {\n padding-right: 1.5rem !important;\n}\n\n.pb-4 {\n padding-bottom: 1.5rem !important;\n}\n\n.pl-4 {\n padding-left: 1.5rem !important;\n}\n\n.px-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n}\n\n.py-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n}\n\n.p-5 {\n padding: 3rem !important;\n}\n\n.pt-5 {\n padding-top: 3rem !important;\n}\n\n.pr-5 {\n padding-right: 3rem !important;\n}\n\n.pb-5 {\n padding-bottom: 3rem !important;\n}\n\n.pl-5 {\n padding-left: 3rem !important;\n}\n\n.px-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n}\n\n.py-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n}\n\n.m-auto {\n margin: auto !important;\n}\n\n.mt-auto {\n margin-top: auto !important;\n}\n\n.mr-auto {\n margin-right: auto !important;\n}\n\n.mb-auto {\n margin-bottom: auto !important;\n}\n\n.ml-auto {\n margin-left: auto !important;\n}\n\n.mx-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n}\n\n.my-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n}\n\n@media (min-width: 576px) {\n .m-sm-0 {\n margin: 0 !important;\n }\n .mt-sm-0 {\n margin-top: 0 !important;\n }\n .mr-sm-0 {\n margin-right: 0 !important;\n }\n .mb-sm-0 {\n margin-bottom: 0 !important;\n }\n .ml-sm-0 {\n margin-left: 0 !important;\n }\n .mx-sm-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .my-sm-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .m-sm-1 {\n margin: 0.25rem !important;\n }\n .mt-sm-1 {\n margin-top: 0.25rem !important;\n }\n .mr-sm-1 {\n margin-right: 0.25rem !important;\n }\n .mb-sm-1 {\n margin-bottom: 0.25rem !important;\n }\n .ml-sm-1 {\n margin-left: 0.25rem !important;\n }\n .mx-sm-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .my-sm-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .m-sm-2 {\n margin: 0.5rem !important;\n }\n .mt-sm-2 {\n margin-top: 0.5rem !important;\n }\n .mr-sm-2 {\n margin-right: 0.5rem !important;\n }\n .mb-sm-2 {\n margin-bottom: 0.5rem !important;\n }\n .ml-sm-2 {\n margin-left: 0.5rem !important;\n }\n .mx-sm-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .my-sm-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .m-sm-3 {\n margin: 1rem !important;\n }\n .mt-sm-3 {\n margin-top: 1rem !important;\n }\n .mr-sm-3 {\n margin-right: 1rem !important;\n }\n .mb-sm-3 {\n margin-bottom: 1rem !important;\n }\n .ml-sm-3 {\n margin-left: 1rem !important;\n }\n .mx-sm-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .my-sm-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .m-sm-4 {\n margin: 1.5rem !important;\n }\n .mt-sm-4 {\n margin-top: 1.5rem !important;\n }\n .mr-sm-4 {\n margin-right: 1.5rem !important;\n }\n .mb-sm-4 {\n margin-bottom: 1.5rem !important;\n }\n .ml-sm-4 {\n margin-left: 1.5rem !important;\n }\n .mx-sm-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .my-sm-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .m-sm-5 {\n margin: 3rem !important;\n }\n .mt-sm-5 {\n margin-top: 3rem !important;\n }\n .mr-sm-5 {\n margin-right: 3rem !important;\n }\n .mb-sm-5 {\n margin-bottom: 3rem !important;\n }\n .ml-sm-5 {\n margin-left: 3rem !important;\n }\n .mx-sm-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .my-sm-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .p-sm-0 {\n padding: 0 !important;\n }\n .pt-sm-0 {\n padding-top: 0 !important;\n }\n .pr-sm-0 {\n padding-right: 0 !important;\n }\n .pb-sm-0 {\n padding-bottom: 0 !important;\n }\n .pl-sm-0 {\n padding-left: 0 !important;\n }\n .px-sm-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .py-sm-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .p-sm-1 {\n padding: 0.25rem !important;\n }\n .pt-sm-1 {\n padding-top: 0.25rem !important;\n }\n .pr-sm-1 {\n padding-right: 0.25rem !important;\n }\n .pb-sm-1 {\n padding-bottom: 0.25rem !important;\n }\n .pl-sm-1 {\n padding-left: 0.25rem !important;\n }\n .px-sm-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .py-sm-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .p-sm-2 {\n padding: 0.5rem !important;\n }\n .pt-sm-2 {\n padding-top: 0.5rem !important;\n }\n .pr-sm-2 {\n padding-right: 0.5rem !important;\n }\n .pb-sm-2 {\n padding-bottom: 0.5rem !important;\n }\n .pl-sm-2 {\n padding-left: 0.5rem !important;\n }\n .px-sm-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .py-sm-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .p-sm-3 {\n padding: 1rem !important;\n }\n .pt-sm-3 {\n padding-top: 1rem !important;\n }\n .pr-sm-3 {\n padding-right: 1rem !important;\n }\n .pb-sm-3 {\n padding-bottom: 1rem !important;\n }\n .pl-sm-3 {\n padding-left: 1rem !important;\n }\n .px-sm-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .py-sm-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .p-sm-4 {\n padding: 1.5rem !important;\n }\n .pt-sm-4 {\n padding-top: 1.5rem !important;\n }\n .pr-sm-4 {\n padding-right: 1.5rem !important;\n }\n .pb-sm-4 {\n padding-bottom: 1.5rem !important;\n }\n .pl-sm-4 {\n padding-left: 1.5rem !important;\n }\n .px-sm-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .py-sm-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .p-sm-5 {\n padding: 3rem !important;\n }\n .pt-sm-5 {\n padding-top: 3rem !important;\n }\n .pr-sm-5 {\n padding-right: 3rem !important;\n }\n .pb-sm-5 {\n padding-bottom: 3rem !important;\n }\n .pl-sm-5 {\n padding-left: 3rem !important;\n }\n .px-sm-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-sm-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .m-sm-auto {\n margin: auto !important;\n }\n .mt-sm-auto {\n margin-top: auto !important;\n }\n .mr-sm-auto {\n margin-right: auto !important;\n }\n .mb-sm-auto {\n margin-bottom: auto !important;\n }\n .ml-sm-auto {\n margin-left: auto !important;\n }\n .mx-sm-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-sm-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n}\n\n@media (min-width: 768px) {\n .m-md-0 {\n margin: 0 !important;\n }\n .mt-md-0 {\n margin-top: 0 !important;\n }\n .mr-md-0 {\n margin-right: 0 !important;\n }\n .mb-md-0 {\n margin-bottom: 0 !important;\n }\n .ml-md-0 {\n margin-left: 0 !important;\n }\n .mx-md-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .my-md-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .m-md-1 {\n margin: 0.25rem !important;\n }\n .mt-md-1 {\n margin-top: 0.25rem !important;\n }\n .mr-md-1 {\n margin-right: 0.25rem !important;\n }\n .mb-md-1 {\n margin-bottom: 0.25rem !important;\n }\n .ml-md-1 {\n margin-left: 0.25rem !important;\n }\n .mx-md-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .my-md-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .m-md-2 {\n margin: 0.5rem !important;\n }\n .mt-md-2 {\n margin-top: 0.5rem !important;\n }\n .mr-md-2 {\n margin-right: 0.5rem !important;\n }\n .mb-md-2 {\n margin-bottom: 0.5rem !important;\n }\n .ml-md-2 {\n margin-left: 0.5rem !important;\n }\n .mx-md-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .my-md-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .m-md-3 {\n margin: 1rem !important;\n }\n .mt-md-3 {\n margin-top: 1rem !important;\n }\n .mr-md-3 {\n margin-right: 1rem !important;\n }\n .mb-md-3 {\n margin-bottom: 1rem !important;\n }\n .ml-md-3 {\n margin-left: 1rem !important;\n }\n .mx-md-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .my-md-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .m-md-4 {\n margin: 1.5rem !important;\n }\n .mt-md-4 {\n margin-top: 1.5rem !important;\n }\n .mr-md-4 {\n margin-right: 1.5rem !important;\n }\n .mb-md-4 {\n margin-bottom: 1.5rem !important;\n }\n .ml-md-4 {\n margin-left: 1.5rem !important;\n }\n .mx-md-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .my-md-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .m-md-5 {\n margin: 3rem !important;\n }\n .mt-md-5 {\n margin-top: 3rem !important;\n }\n .mr-md-5 {\n margin-right: 3rem !important;\n }\n .mb-md-5 {\n margin-bottom: 3rem !important;\n }\n .ml-md-5 {\n margin-left: 3rem !important;\n }\n .mx-md-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .my-md-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .p-md-0 {\n padding: 0 !important;\n }\n .pt-md-0 {\n padding-top: 0 !important;\n }\n .pr-md-0 {\n padding-right: 0 !important;\n }\n .pb-md-0 {\n padding-bottom: 0 !important;\n }\n .pl-md-0 {\n padding-left: 0 !important;\n }\n .px-md-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .py-md-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .p-md-1 {\n padding: 0.25rem !important;\n }\n .pt-md-1 {\n padding-top: 0.25rem !important;\n }\n .pr-md-1 {\n padding-right: 0.25rem !important;\n }\n .pb-md-1 {\n padding-bottom: 0.25rem !important;\n }\n .pl-md-1 {\n padding-left: 0.25rem !important;\n }\n .px-md-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .py-md-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .p-md-2 {\n padding: 0.5rem !important;\n }\n .pt-md-2 {\n padding-top: 0.5rem !important;\n }\n .pr-md-2 {\n padding-right: 0.5rem !important;\n }\n .pb-md-2 {\n padding-bottom: 0.5rem !important;\n }\n .pl-md-2 {\n padding-left: 0.5rem !important;\n }\n .px-md-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .py-md-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .p-md-3 {\n padding: 1rem !important;\n }\n .pt-md-3 {\n padding-top: 1rem !important;\n }\n .pr-md-3 {\n padding-right: 1rem !important;\n }\n .pb-md-3 {\n padding-bottom: 1rem !important;\n }\n .pl-md-3 {\n padding-left: 1rem !important;\n }\n .px-md-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .py-md-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .p-md-4 {\n padding: 1.5rem !important;\n }\n .pt-md-4 {\n padding-top: 1.5rem !important;\n }\n .pr-md-4 {\n padding-right: 1.5rem !important;\n }\n .pb-md-4 {\n padding-bottom: 1.5rem !important;\n }\n .pl-md-4 {\n padding-left: 1.5rem !important;\n }\n .px-md-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .py-md-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .p-md-5 {\n padding: 3rem !important;\n }\n .pt-md-5 {\n padding-top: 3rem !important;\n }\n .pr-md-5 {\n padding-right: 3rem !important;\n }\n .pb-md-5 {\n padding-bottom: 3rem !important;\n }\n .pl-md-5 {\n padding-left: 3rem !important;\n }\n .px-md-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-md-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .m-md-auto {\n margin: auto !important;\n }\n .mt-md-auto {\n margin-top: auto !important;\n }\n .mr-md-auto {\n margin-right: auto !important;\n }\n .mb-md-auto {\n margin-bottom: auto !important;\n }\n .ml-md-auto {\n margin-left: auto !important;\n }\n .mx-md-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-md-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n}\n\n@media (min-width: 992px) {\n .m-lg-0 {\n margin: 0 !important;\n }\n .mt-lg-0 {\n margin-top: 0 !important;\n }\n .mr-lg-0 {\n margin-right: 0 !important;\n }\n .mb-lg-0 {\n margin-bottom: 0 !important;\n }\n .ml-lg-0 {\n margin-left: 0 !important;\n }\n .mx-lg-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .my-lg-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .m-lg-1 {\n margin: 0.25rem !important;\n }\n .mt-lg-1 {\n margin-top: 0.25rem !important;\n }\n .mr-lg-1 {\n margin-right: 0.25rem !important;\n }\n .mb-lg-1 {\n margin-bottom: 0.25rem !important;\n }\n .ml-lg-1 {\n margin-left: 0.25rem !important;\n }\n .mx-lg-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .my-lg-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .m-lg-2 {\n margin: 0.5rem !important;\n }\n .mt-lg-2 {\n margin-top: 0.5rem !important;\n }\n .mr-lg-2 {\n margin-right: 0.5rem !important;\n }\n .mb-lg-2 {\n margin-bottom: 0.5rem !important;\n }\n .ml-lg-2 {\n margin-left: 0.5rem !important;\n }\n .mx-lg-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .my-lg-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .m-lg-3 {\n margin: 1rem !important;\n }\n .mt-lg-3 {\n margin-top: 1rem !important;\n }\n .mr-lg-3 {\n margin-right: 1rem !important;\n }\n .mb-lg-3 {\n margin-bottom: 1rem !important;\n }\n .ml-lg-3 {\n margin-left: 1rem !important;\n }\n .mx-lg-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .my-lg-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .m-lg-4 {\n margin: 1.5rem !important;\n }\n .mt-lg-4 {\n margin-top: 1.5rem !important;\n }\n .mr-lg-4 {\n margin-right: 1.5rem !important;\n }\n .mb-lg-4 {\n margin-bottom: 1.5rem !important;\n }\n .ml-lg-4 {\n margin-left: 1.5rem !important;\n }\n .mx-lg-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .my-lg-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .m-lg-5 {\n margin: 3rem !important;\n }\n .mt-lg-5 {\n margin-top: 3rem !important;\n }\n .mr-lg-5 {\n margin-right: 3rem !important;\n }\n .mb-lg-5 {\n margin-bottom: 3rem !important;\n }\n .ml-lg-5 {\n margin-left: 3rem !important;\n }\n .mx-lg-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .my-lg-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .p-lg-0 {\n padding: 0 !important;\n }\n .pt-lg-0 {\n padding-top: 0 !important;\n }\n .pr-lg-0 {\n padding-right: 0 !important;\n }\n .pb-lg-0 {\n padding-bottom: 0 !important;\n }\n .pl-lg-0 {\n padding-left: 0 !important;\n }\n .px-lg-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .py-lg-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .p-lg-1 {\n padding: 0.25rem !important;\n }\n .pt-lg-1 {\n padding-top: 0.25rem !important;\n }\n .pr-lg-1 {\n padding-right: 0.25rem !important;\n }\n .pb-lg-1 {\n padding-bottom: 0.25rem !important;\n }\n .pl-lg-1 {\n padding-left: 0.25rem !important;\n }\n .px-lg-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .py-lg-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .p-lg-2 {\n padding: 0.5rem !important;\n }\n .pt-lg-2 {\n padding-top: 0.5rem !important;\n }\n .pr-lg-2 {\n padding-right: 0.5rem !important;\n }\n .pb-lg-2 {\n padding-bottom: 0.5rem !important;\n }\n .pl-lg-2 {\n padding-left: 0.5rem !important;\n }\n .px-lg-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .py-lg-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .p-lg-3 {\n padding: 1rem !important;\n }\n .pt-lg-3 {\n padding-top: 1rem !important;\n }\n .pr-lg-3 {\n padding-right: 1rem !important;\n }\n .pb-lg-3 {\n padding-bottom: 1rem !important;\n }\n .pl-lg-3 {\n padding-left: 1rem !important;\n }\n .px-lg-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .py-lg-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .p-lg-4 {\n padding: 1.5rem !important;\n }\n .pt-lg-4 {\n padding-top: 1.5rem !important;\n }\n .pr-lg-4 {\n padding-right: 1.5rem !important;\n }\n .pb-lg-4 {\n padding-bottom: 1.5rem !important;\n }\n .pl-lg-4 {\n padding-left: 1.5rem !important;\n }\n .px-lg-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .py-lg-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .p-lg-5 {\n padding: 3rem !important;\n }\n .pt-lg-5 {\n padding-top: 3rem !important;\n }\n .pr-lg-5 {\n padding-right: 3rem !important;\n }\n .pb-lg-5 {\n padding-bottom: 3rem !important;\n }\n .pl-lg-5 {\n padding-left: 3rem !important;\n }\n .px-lg-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-lg-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .m-lg-auto {\n margin: auto !important;\n }\n .mt-lg-auto {\n margin-top: auto !important;\n }\n .mr-lg-auto {\n margin-right: auto !important;\n }\n .mb-lg-auto {\n margin-bottom: auto !important;\n }\n .ml-lg-auto {\n margin-left: auto !important;\n }\n .mx-lg-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-lg-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n}\n\n@media (min-width: 1200px) {\n .m-xl-0 {\n margin: 0 !important;\n }\n .mt-xl-0 {\n margin-top: 0 !important;\n }\n .mr-xl-0 {\n margin-right: 0 !important;\n }\n .mb-xl-0 {\n margin-bottom: 0 !important;\n }\n .ml-xl-0 {\n margin-left: 0 !important;\n }\n .mx-xl-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .my-xl-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .m-xl-1 {\n margin: 0.25rem !important;\n }\n .mt-xl-1 {\n margin-top: 0.25rem !important;\n }\n .mr-xl-1 {\n margin-right: 0.25rem !important;\n }\n .mb-xl-1 {\n margin-bottom: 0.25rem !important;\n }\n .ml-xl-1 {\n margin-left: 0.25rem !important;\n }\n .mx-xl-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .my-xl-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .m-xl-2 {\n margin: 0.5rem !important;\n }\n .mt-xl-2 {\n margin-top: 0.5rem !important;\n }\n .mr-xl-2 {\n margin-right: 0.5rem !important;\n }\n .mb-xl-2 {\n margin-bottom: 0.5rem !important;\n }\n .ml-xl-2 {\n margin-left: 0.5rem !important;\n }\n .mx-xl-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .my-xl-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .m-xl-3 {\n margin: 1rem !important;\n }\n .mt-xl-3 {\n margin-top: 1rem !important;\n }\n .mr-xl-3 {\n margin-right: 1rem !important;\n }\n .mb-xl-3 {\n margin-bottom: 1rem !important;\n }\n .ml-xl-3 {\n margin-left: 1rem !important;\n }\n .mx-xl-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .my-xl-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .m-xl-4 {\n margin: 1.5rem !important;\n }\n .mt-xl-4 {\n margin-top: 1.5rem !important;\n }\n .mr-xl-4 {\n margin-right: 1.5rem !important;\n }\n .mb-xl-4 {\n margin-bottom: 1.5rem !important;\n }\n .ml-xl-4 {\n margin-left: 1.5rem !important;\n }\n .mx-xl-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .my-xl-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .m-xl-5 {\n margin: 3rem !important;\n }\n .mt-xl-5 {\n margin-top: 3rem !important;\n }\n .mr-xl-5 {\n margin-right: 3rem !important;\n }\n .mb-xl-5 {\n margin-bottom: 3rem !important;\n }\n .ml-xl-5 {\n margin-left: 3rem !important;\n }\n .mx-xl-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .my-xl-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .p-xl-0 {\n padding: 0 !important;\n }\n .pt-xl-0 {\n padding-top: 0 !important;\n }\n .pr-xl-0 {\n padding-right: 0 !important;\n }\n .pb-xl-0 {\n padding-bottom: 0 !important;\n }\n .pl-xl-0 {\n padding-left: 0 !important;\n }\n .px-xl-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .py-xl-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .p-xl-1 {\n padding: 0.25rem !important;\n }\n .pt-xl-1 {\n padding-top: 0.25rem !important;\n }\n .pr-xl-1 {\n padding-right: 0.25rem !important;\n }\n .pb-xl-1 {\n padding-bottom: 0.25rem !important;\n }\n .pl-xl-1 {\n padding-left: 0.25rem !important;\n }\n .px-xl-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .py-xl-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .p-xl-2 {\n padding: 0.5rem !important;\n }\n .pt-xl-2 {\n padding-top: 0.5rem !important;\n }\n .pr-xl-2 {\n padding-right: 0.5rem !important;\n }\n .pb-xl-2 {\n padding-bottom: 0.5rem !important;\n }\n .pl-xl-2 {\n padding-left: 0.5rem !important;\n }\n .px-xl-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .py-xl-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .p-xl-3 {\n padding: 1rem !important;\n }\n .pt-xl-3 {\n padding-top: 1rem !important;\n }\n .pr-xl-3 {\n padding-right: 1rem !important;\n }\n .pb-xl-3 {\n padding-bottom: 1rem !important;\n }\n .pl-xl-3 {\n padding-left: 1rem !important;\n }\n .px-xl-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .py-xl-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .p-xl-4 {\n padding: 1.5rem !important;\n }\n .pt-xl-4 {\n padding-top: 1.5rem !important;\n }\n .pr-xl-4 {\n padding-right: 1.5rem !important;\n }\n .pb-xl-4 {\n padding-bottom: 1.5rem !important;\n }\n .pl-xl-4 {\n padding-left: 1.5rem !important;\n }\n .px-xl-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .py-xl-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .p-xl-5 {\n padding: 3rem !important;\n }\n .pt-xl-5 {\n padding-top: 3rem !important;\n }\n .pr-xl-5 {\n padding-right: 3rem !important;\n }\n .pb-xl-5 {\n padding-bottom: 3rem !important;\n }\n .pl-xl-5 {\n padding-left: 3rem !important;\n }\n .px-xl-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-xl-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .m-xl-auto {\n margin: auto !important;\n }\n .mt-xl-auto {\n margin-top: auto !important;\n }\n .mr-xl-auto {\n margin-right: auto !important;\n }\n .mb-xl-auto {\n margin-bottom: auto !important;\n }\n .ml-xl-auto {\n margin-left: auto !important;\n }\n .mx-xl-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-xl-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n}\n\n.text-justify {\n text-align: justify !important;\n}\n\n.text-nowrap {\n white-space: nowrap !important;\n}\n\n.text-truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.text-left {\n text-align: left !important;\n}\n\n.text-right {\n text-align: right !important;\n}\n\n.text-center {\n text-align: center !important;\n}\n\n@media (min-width: 576px) {\n .text-sm-left {\n text-align: left !important;\n }\n .text-sm-right {\n text-align: right !important;\n }\n .text-sm-center {\n text-align: center !important;\n }\n}\n\n@media (min-width: 768px) {\n .text-md-left {\n text-align: left !important;\n }\n .text-md-right {\n text-align: right !important;\n }\n .text-md-center {\n text-align: center !important;\n }\n}\n\n@media (min-width: 992px) {\n .text-lg-left {\n text-align: left !important;\n }\n .text-lg-right {\n text-align: right !important;\n }\n .text-lg-center {\n text-align: center !important;\n }\n}\n\n@media (min-width: 1200px) {\n .text-xl-left {\n text-align: left !important;\n }\n .text-xl-right {\n text-align: right !important;\n }\n .text-xl-center {\n text-align: center !important;\n }\n}\n\n.text-lowercase {\n text-transform: lowercase !important;\n}\n\n.text-uppercase {\n text-transform: uppercase !important;\n}\n\n.text-capitalize {\n text-transform: capitalize !important;\n}\n\n.font-weight-normal {\n font-weight: normal;\n}\n\n.font-weight-bold {\n font-weight: bold;\n}\n\n.font-italic {\n font-style: italic;\n}\n\n.text-white {\n color: #fff !important;\n}\n\n.text-primary {\n color: #007bff !important;\n}\n\na.text-primary:focus, a.text-primary:hover {\n color: #0062cc !important;\n}\n\n.text-secondary {\n color: #868e96 !important;\n}\n\na.text-secondary:focus, a.text-secondary:hover {\n color: #6c757d !important;\n}\n\n.text-success {\n color: #28a745 !important;\n}\n\na.text-success:focus, a.text-success:hover {\n color: #1e7e34 !important;\n}\n\n.text-info {\n color: #17a2b8 !important;\n}\n\na.text-info:focus, a.text-info:hover {\n color: #117a8b !important;\n}\n\n.text-warning {\n color: #ffc107 !important;\n}\n\na.text-warning:focus, a.text-warning:hover {\n color: #d39e00 !important;\n}\n\n.text-danger {\n color: #dc3545 !important;\n}\n\na.text-danger:focus, a.text-danger:hover {\n color: #bd2130 !important;\n}\n\n.text-light {\n color: #f8f9fa !important;\n}\n\na.text-light:focus, a.text-light:hover {\n color: #dae0e5 !important;\n}\n\n.text-dark {\n color: #343a40 !important;\n}\n\na.text-dark:focus, a.text-dark:hover {\n color: #1d2124 !important;\n}\n\n.text-muted {\n color: #ced4da !important;\n}\n\n.text-hide {\n font: 0/0 a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n\n.visible {\n visibility: visible !important;\n}\n\n.invisible {\n visibility: hidden !important;\n}\n\n/*# sourceMappingURL=bootstrap.css.map */",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]} \ No newline at end of file
+{"version":3,"sources":["../../scss/bootstrap.scss","../../scss/_print.scss","bootstrap.css","../../scss/_reboot.scss","../../scss/_variables.scss","../../scss/mixins/_hover.scss","../../scss/_type.scss","../../scss/mixins/_lists.scss","../../scss/_images.scss","../../scss/mixins/_image.scss","../../scss/mixins/_border-radius.scss","../../scss/mixins/_transition.scss","../../scss/_code.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/mixins/_breakpoints.scss","../../scss/mixins/_grid-framework.scss","../../scss/_tables.scss","../../scss/mixins/_table-row.scss","../../scss/_functions.scss","../../scss/_forms.scss","../../scss/mixins/_forms.scss","../../scss/_buttons.scss","../../scss/mixins/_buttons.scss","../../scss/_transitions.scss","../../scss/_dropdown.scss","../../scss/mixins/_nav-divider.scss","../../scss/_button-group.scss","../../scss/_input-group.scss","../../scss/_custom-forms.scss","../../scss/_nav.scss","../../scss/_navbar.scss","../../scss/_card.scss","../../scss/_breadcrumb.scss","../../scss/mixins/_clearfix.scss","../../scss/_pagination.scss","../../scss/mixins/_pagination.scss","../../scss/_badge.scss","../../scss/mixins/_badge.scss","../../scss/_jumbotron.scss","../../scss/_alert.scss","../../scss/mixins/_alert.scss","../../scss/_progress.scss","../../scss/mixins/_gradients.scss","../../scss/_media.scss","../../scss/_list-group.scss","../../scss/mixins/_list-group.scss","../../scss/_close.scss","../../scss/_modal.scss","../../scss/_tooltip.scss","../../scss/mixins/_reset-text.scss","../../scss/_popover.scss","../../scss/_carousel.scss","../../scss/utilities/_align.scss","../../scss/mixins/_background-variant.scss","../../scss/utilities/_background.scss","../../scss/utilities/_borders.scss","../../scss/utilities/_display.scss","../../scss/utilities/_embed.scss","../../scss/utilities/_flex.scss","../../scss/utilities/_float.scss","../../scss/mixins/_float.scss","../../scss/utilities/_position.scss","../../scss/utilities/_screenreaders.scss","../../scss/mixins/_screen-reader.scss","../../scss/utilities/_sizing.scss","../../scss/utilities/_spacing.scss","../../scss/utilities/_text.scss","../../scss/mixins/_text-truncate.scss","../../scss/mixins/_text-emphasis.scss","../../scss/mixins/_text-hide.scss","../../scss/utilities/_visibility.scss","../../scss/mixins/_visibility.scss"],"names":[],"mappings":"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AAED;;EAGE,0BAhCqF;EAiCrF,uBAAsB;EACtB,sBAlC2H;CAoC5H;;ADkBD;ECdA,enB6Be;EmB5Bf,8BAA6B;EAC7B,uBAAsB;EACtB,sBnB0Be;CkBbd;;AjBlDC;EkBwCA,YDS4C;ECR5C,0BnBsBa;EmBrBb,sBnBqBa;CC/DQ;;AkB6CvB;EAEE,6CnBgBa;CmBfd;;AAED;EAEE,enBWa;EmBVb,8BAA6B;CAC9B;;AAED;;EAGE,YDV4C;ECW5C,0BnBGa;EmBFb,sBnBEa;CmBDd;;ADdD;ECdA,enBWgB;EmBVhB,8BAA6B;EAC7B,uBAAsB;EACtB,sBnBQgB;CkBKf;;AjBlDC;EkBwCA,YDS4C;ECR5C,0BnBIc;EmBHd,sBnBGc;CC7CO;;AkB6CvB;EAEE,+CnBFc;CmBGf;;AAED;EAEE,enBPc;EmBQd,8BAA6B;CAC9B;;AAED;;EAGE,YDV4C;ECW5C,0BnBfc;EmBgBd,sBnBhBc;CmBiBf;;ADdD;ECdA,enBoCe;EmBnCf,8BAA6B;EAC7B,uBAAsB;EACtB,sBnBiCe;CkBpBd;;AjBlDC;EkBwCA,YDS4C;ECR5C,0BnB6Ba;EmB5Bb,sBnB4Ba;CCtEQ;;AkB6CvB;EAEE,6CnBuBa;CmBtBd;;AAED;EAEE,enBkBa;EmBjBb,8BAA6B;CAC9B;;AAED;;EAGE,YDV4C;ECW5C,0BnBUa;EmBTb,sBnBSa;CmBRd;;ADdD;ECdA,enBsCe;EmBrCf,8BAA6B;EAC7B,uBAAsB;EACtB,sBnBmCe;CkBtBd;;AjBlDC;EkBwCA,YDS4C;ECR5C,0BnB+Ba;EmB9Bb,sBnB8Ba;CCxEQ;;AkB6CvB;EAEE,8CnByBa;CmBxBd;;AAED;EAEE,enBoBa;EmBnBb,8BAA6B;CAC9B;;AAED;;EAGE,YDV4C;ECW5C,0BnBYa;EmBXb,sBnBWa;CmBVd;;ADdD;ECdA,enBmCe;EmBlCf,8BAA6B;EAC7B,uBAAsB;EACtB,sBnBgCe;CkBnBd;;AjBlDC;EkBwCA,YDS4C;ECR5C,0BnB4Ba;EmB3Bb,sBnB2Ba;CCrEQ;;AkB6CvB;EAEE,6CnBsBa;CmBrBd;;AAED;EAEE,enBiBa;EmBhBb,8BAA6B;CAC9B;;AAED;;EAGE,YDV4C;ECW5C,0BnBSa;EmBRb,sBnBQa;CmBPd;;ADdD;ECdA,enBiCe;EmBhCf,8BAA6B;EAC7B,uBAAsB;EACtB,sBnB8Be;CkBjBd;;AjBlDC;EkBwCA,YDS4C;ECR5C,0BnB0Ba;EmBzBb,sBnByBa;CCnEQ;;AkB6CvB;EAEE,6CnBoBa;CmBnBd;;AAED;EAEE,enBea;EmBdb,8BAA6B;CAC9B;;AAED;;EAGE,YDV4C;ECW5C,0BnBOa;EmBNb,sBnBMa;CmBLd;;ADdD;ECdA,enBMgB;EmBLhB,8BAA6B;EAC7B,uBAAsB;EACtB,sBnBGgB;CkBUf;;AjBlDC;EkBwCA,YDS4C;ECR5C,0BnBDc;EmBEd,sBnBFc;CCxCO;;AkB6CvB;EAEE,+CnBPc;CmBQf;;AAED;EAEE,enBZc;EmBad,8BAA6B;CAC9B;;AAED;;EAGE,YDV4C;ECW5C,0BnBpBc;EmBqBd,sBnBrBc;CmBsBf;;ADdD;ECdA,enBagB;EmBZhB,8BAA6B;EAC7B,uBAAsB;EACtB,sBnBUgB;CkBGf;;AjBlDC;EkBwCA,YDS4C;ECR5C,0BnBMc;EmBLd,sBnBKc;CC/CO;;AkB6CvB;EAEE,4CnBAc;CmBCf;;AAED;EAEE,enBLc;EmBMd,8BAA6B;CAC9B;;AAED;;EAGE,YDV4C;ECW5C,0BnBbc;EmBcd,sBnBdc;CmBef;;ADHH;EACE,oBlB0KyB;EkBzKzB,elBEe;EkBDf,iBAAgB;CA6BjB;;AAhCD;EASI,8BAA6B;CAE9B;;AAXH;EAeI,0BAAyB;CAC1B;;AjB3EC;EiB6EA,0BAAyB;CjB7EJ;;AAWrB;EiBqEA,elB2E4C;EkB1E5C,2BlB2E6B;EkB1E7B,8BAA6B;CjBpE5B;;AiB6CL;EA0BI,elBxCc;CkB6Cf;;AjB/EC;EiB6EE,sBAAqB;CjB1EtB;;AiBoFL;EC/BE,qBnBgQ8B;EmB/P9B,mBnB+JsB;EmB9JtB,iBnBkI0B;EM9MxB,sBNoN0B;CkBzG7B;;AAED;ECnCE,wBnB4P+B;EmB3P/B,oBnBgKsB;EmB/JtB,iBnBmI0B;EM/MxB,sBNqN0B;CkBtG7B;;AAOD;EACE,eAAc;EACd,YAAW;CACZ;;AAGD;EACE,mBlB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B;EA7BT;IA+BU,6BAA4B;GAC7B;EAhCT;IAoCQ,iBAAgB;GAMjB;EA1CP;;IAwCU,iBAAgB;GACjB;C9B2zGV;;A8B/yGD;EAEI,uB5BkZ6B;C4BjZ9B;;AjB3JC;EiBwJJ;IAMI,wB5B2ZyB;O4B3ZzB,qB5B2ZyB;Y4B3ZzB,gB5B2ZyB;I4B1ZzB,4B5B2Z+B;O4B3Z/B,yB5B2Z+B;Y4B3Z/B,oB5B2Z+B;G4BpZlC;EAdD;IAUM,sBAAqB;IACrB,YAAW;GACZ;C9BkzGJ;;A+B9gHD;EACE,sB7BixBkC;E6BhxBlC,oBAAmB;EACnB,iBAAgB;EAChB,0B7BgDgB;EMhDd,uBNmN2B;C6BhN9B;;ACNC;EACE,eAAc;EACd,YAAW;EACX,YAAW;CACZ;;ADIH;EACE,YAAW;CA2BZ;;AA5BD;EAKI,sBAAqB;EACrB,sB7BowBiC;E6BnwBjC,qB7BmwBiC;E6BlwBjC,e7BuCc;E6BtCd,aAAiC;CAClC;;AAVH;EAmBI,2BAA0B;CAC3B;;AApBH;EAsBI,sBAAqB;CACtB;;AAvBH;EA0BI,e7BqBc;C6BpBf;;AEpCH;EACE,qBAAa;EAAb,cAAa;EAEb,gBAAe;EACf,iBAAgB;EzBAd,uBNmN2B;C+BjN9B;;AAED;EAGM,eAAc;EzBoBhB,gCNwL2B;EMvL3B,mCNuL2B;C+B1M1B;;AALL;EzBSI,iCNsM2B;EMrM3B,oCNqM2B;C+BrM1B;;AAVL;EAcI,WAAU;EACV,Y/B2BS;E+B1BT,0B/BkDa;E+BjDb,sB/BiDa;C+BhDd;;AAlBH;EAqBI,e/B2Bc;E+B1Bd,qBAAoB;EACpB,uB/BmBS;E+BlBT,mB/ByjBuC;C+BxjBxC;;AAGH;EACE,mBAAkB;EAClB,eAAc;EACd,wB/B4hB0C;E+B3hB1C,kBAAiB;EACjB,kB/B+hBwC;E+B9hBxC,e/BgCe;E+B/Bf,uB/BOW;E+BNX,uB/BiiByC;C+BzhB1C;;A9B9BG;E8ByBA,e/BuH4C;E+BtH5C,sBAAqB;EACrB,0B/BGc;E+BFd,mB/B+hBuC;CCxjBtC;;A+BtBH;EACE,wBhCmkBwC;EgClkBxC,mBhCyOoB;EgCxOpB,iBhC4MwB;CgC3MzB;;AAIG;E1BoBF,+BNyL0B;EMxL1B,kCNwL0B;CgC3MvB;;AAGD;E1BCF,gCNuM0B;EMtM1B,mCNsM0B;CgCtMvB;;AAfL;EACE,wBhCikBuC;EgChkBvC,oBhC0OoB;EgCzOpB,iBhC6MwB;CgC5MzB;;AAIG;E1BoBF,+BN0L0B;EMzL1B,kCNyL0B;CgC5MvB;;AAGD;E1BCF,gCNwM0B;EMvM1B,mCNuM0B;CgCvMvB;;ACbP;EACE,sBAAqB;EACrB,sBjC+pBgC;EiC9pBhC,ejC2pB+B;EiC1pB/B,kBjCyOqB;EiCxOrB,eAAc;EACd,YjCuCW;EiCtCX,mBAAkB;EAClB,oBAAmB;EACnB,yBAAwB;E3BVtB,uBNmN2B;CiClM9B;;AAhBD;EAcI,cAAa;CACd;;AAIH;EACE,mBAAkB;EAClB,UAAS;CACV;;AAMD;EACE,qBjCsoBgC;EiCroBhC,oBjCqoBgC;EMpqB9B,qBNuqB+B;CiCtoBlC;;AAOC;ElBiBE,YAAW;EmB3Db,0BlCwEe;CiC5Bd;;AhCxBC;EcuCA,YAAW;EmBtDT,sBAAqB;EACrB,0BAAkC;CjCiBnC;;AgCmBH;ElBiBE,YAAW;EmB3Db,0BlCsDgB;CiCVf;;AhCxBC;EcuCA,YAAW;EmBtDT,sBAAqB;EACrB,0BAAkC;CjCiBnC;;AgCmBH;ElBiBE,YAAW;EmB3Db,0BlC+Ee;CiCnCd;;AhCxBC;EcuCA,YAAW;EmBtDT,sBAAqB;EACrB,0BAAkC;CjCiBnC;;AgCmBH;ElBiBE,YAAW;EmB3Db,0BlCiFe;CiCrCd;;AhCxBC;EcuCA,YAAW;EmBtDT,sBAAqB;EACrB,0BAAkC;CjCiBnC;;AgCmBH;ElBeE,YAAW;EmBzDb,0BlC8Ee;CiClCd;;AhCxBC;EcqCA,YAAW;EmBpDT,sBAAqB;EACrB,0BAAkC;CjCiBnC;;AgCmBH;ElBiBE,YAAW;EmB3Db,0BlC4Ee;CiChCd;;AhCxBC;EcuCA,YAAW;EmBtDT,sBAAqB;EACrB,0BAAkC;CjCiBnC;;AgCmBH;ElBeE,YAAW;EmBzDb,0BlCiDgB;CiCLf;;AhCxBC;EcqCA,YAAW;EmBpDT,sBAAqB;EACrB,0BAAkC;CjCiBnC;;AgCmBH;ElBiBE,YAAW;EmB3Db,0BlCwDgB;CiCZf;;AhCxBC;EcuCA,YAAW;EmBtDT,sBAAqB;EACrB,0BAAkC;CjCiBnC;;AkCzBL;EACE,mBAAoD;EACpD,oBnC4lBmC;EmC3lBnC,0BnCiDgB;EMhDd,sBNoN0B;CmC/M7B;;AxB+CG;EwBxDJ;IAOI,mBnCulBiC;GmCrlBpC;CrC8vHA;;AqC5vHD;EACE,iBAAgB;EAChB,gBAAe;E7BTb,iB6BUsB;CACzB;;ACXD;EACE,yBpC6sBmC;EoC5sBnC,oBpC6sBgC;EoC5sBhC,8BAA6C;E9BH3C,uBNmN2B;CoC9M9B;;AAGD;EAEE,eAAc;CACf;;AAGD;EACE,kBpC+NqB;CoC9NtB;;AAOD;EAGI,mBAAkB;EAClB,cpCkrBgC;EoCjrBhC,gBpCkrBiC;EoCjrBjC,yBpCirBiC;EoChrBjC,eAAc;CACf;;AASD;EC3CA,etBsFkE;EsBrFlE,0BtBmFuE;EsBlFvE,sBtBkFuE;CqBvCtE;;ACzCD;EACE,0BAAqC;CACtC;;AAED;EACE,eAA0B;CAC3B;;ADiCD;EC3CA,etBsFkE;EsBrFlE,0BtBmFuE;EsBlFvE,sBtBkFuE;CqBvCtE;;ACzCD;EACE,0BAAqC;CACtC;;AAED;EACE,eAA0B;CAC3B;;ADiCD;EC3CA,etBsFkE;EsBrFlE,0BtBmFuE;EsBlFvE,sBtBkFuE;CqBvCtE;;ACzCD;EACE,0BAAqC;CACtC;;AAED;EACE,eAA0B;CAC3B;;ADiCD;EC3CA,etBsFkE;EsBrFlE,0BtBmFuE;EsBlFvE,sBtBkFuE;CqBvCtE;;ACzCD;EACE,0BAAqC;CACtC;;AAED;EACE,eAA0B;CAC3B;;ADiCD;EC3CA,etBsFkE;EsBrFlE,0BtBmFuE;EsBlFvE,sBtBkFuE;CqBvCtE;;ACzCD;EACE,0BAAqC;CACtC;;AAED;EACE,eAA0B;CAC3B;;ADiCD;EC3CA,etBsFkE;EsBrFlE,0BtBmFuE;EsBlFvE,sBtBkFuE;CqBvCtE;;ACzCD;EACE,0BAAqC;CACtC;;AAED;EACE,eAA0B;CAC3B;;ADiCD;EC3CA,etBsFkE;EsBrFlE,0BtBmFuE;EsBlFvE,sBtBkFuE;CqBvCtE;;ACzCD;EACE,0BAAqC;CACtC;;AAED;EACE,eAA0B;CAC3B;;ADiCD;EC3CA,etBsFkE;EsBrFlE,0BtBmFuE;EsBlFvE,sBtBkFuE;CqBvCtE;;ACzCD;EACE,0BAAqC;CACtC;;AAED;EACE,eAA0B;CAC3B;;ACXH;EACE;IAAO,4BAAuC;GxCw5H7C;EwCv5HD;IAAK,yBAAwB;GxC05H5B;CACF;;AwC75HD;EACE;IAAO,4BAAuC;GxCw5H7C;EwCv5HD;IAAK,yBAAwB;GxC05H5B;CACF;;AwCx5HD;EACE,qBAAa;EAAb,cAAa;EACb,iBAAgB;EAChB,mBtCotBoC;EsCntBpC,kBtCktBkC;EsCjtBlC,mBAAkB;EAClB,0BtCyCgB;EMhDd,uBNmN2B;CsCzM9B;;AAED;EACE,atC0sBkC;EsCzsBlC,kBtCysBkC;EsCxsBlC,YtC+BW;EsC9BX,0BtCsDe;EOrEX,4BP8tBwC;CsC7sB7C;;AAED;ECWE,sMAA6I;EDT7I,2BtCisBkC;CsChsBnC;;AAED;EACE,2DtCosBgD;UsCpsBhD,mDtCosBgD;CsCnsBjD;;AE/BD;EACE,qBAAa;EAAb,cAAa;EACb,sBAAuB;MAAvB,wBAAuB;CACxB;;AAED;EACE,YAAO;MAAP,QAAO;CACR;;ACHD;EACE,qBAAa;EAAb,cAAa;EACb,2BAAsB;MAAtB,uBAAsB;EAGtB,gBAAe;EACf,iBAAgB;CACjB;;AAQD;EACE,YAAW;EACX,ezCoCgB;EyCnChB,oBAAmB;CAapB;;AxCbG;EwCIA,ezC+Bc;EyC9Bd,sBAAqB;EACrB,0BzCuBc;CC1Bb;;AwCNL;EAaI,ezC2Bc;EyC1Bd,0BzCmBc;CyClBf;;AAQH;EACE,mBAAkB;EAClB,eAAc;EACd,yBzCgsBsC;EyC9rBtC,oBzCsKgB;EyCrKhB,uBzCEW;EyCDX,uCzCWW;CyCiBZ;;AAnCD;EnChCI,gCN6M2B;EM5M3B,iCN4M2B;CyClK5B;;AAXH;EAcI,iBAAgB;EnChChB,oCN+L2B;EM9L3B,mCN8L2B;CyC7J5B;;AxCpCC;EwCuCA,sBAAqB;CxCpCpB;;AwCiBL;EAwBI,ezCVc;EyCWd,uBzCjBS;CyCkBV;;AA1BH;EA8BI,WAAU;EACV,YzCvBS;EyCwBT,0BzCAa;EyCCb,sBzCDa;CyCEd;;AASH;EAEI,gBAAe;EACf,eAAc;EACd,iBAAgB;CACjB;;AALH;EASM,cAAa;CACd;;AAVL;EAeM,iBAAgB;CACjB;;AClGH;EACE,e3BmFgE;E2BlFhE,0B3BgFqE;C2B/EtE;;AAGD;;EAEE,e3B4EgE;C2BhEjE;;AzCDC;;;EyCRE,e3ByE8D;E2BxE9D,0BAAyC;CzCU1C;;AyChBH;;EAUI,YAAW;EACX,0B3BmE8D;E2BlE9D,sB3BkE8D;C2BjE/D;;AAnBH;EACE,e3BmFgE;E2BlFhE,0B3BgFqE;C2B/EtE;;AAGD;;EAEE,e3B4EgE;C2BhEjE;;AzCDC;;;EyCRE,e3ByE8D;E2BxE9D,0BAAyC;CzCU1C;;AyChBH;;EAUI,YAAW;EACX,0B3BmE8D;E2BlE9D,sB3BkE8D;C2BjE/D;;AAnBH;EACE,e3BmFgE;E2BlFhE,0B3BgFqE;C2B/EtE;;AAGD;;EAEE,e3B4EgE;C2BhEjE;;AzCDC;;;EyCRE,e3ByE8D;E2BxE9D,0BAAyC;CzCU1C;;AyChBH;;EAUI,YAAW;EACX,0B3BmE8D;E2BlE9D,sB3BkE8D;C2BjE/D;;AAnBH;EACE,e3BmFgE;E2BlFhE,0B3BgFqE;C2B/EtE;;AAGD;;EAEE,e3B4EgE;C2BhEjE;;AzCDC;;;EyCRE,e3ByE8D;E2BxE9D,0BAAyC;CzCU1C;;AyChBH;;EAUI,YAAW;EACX,0B3BmE8D;E2BlE9D,sB3BkE8D;C2BjE/D;;AAnBH;EACE,e3BmFgE;E2BlFhE,0B3BgFqE;C2B/EtE;;AAGD;;EAEE,e3B4EgE;C2BhEjE;;AzCDC;;;EyCRE,e3ByE8D;E2BxE9D,0BAAyC;CzCU1C;;AyChBH;;EAUI,YAAW;EACX,0B3BmE8D;E2BlE9D,sB3BkE8D;C2BjE/D;;AAnBH;EACE,e3BmFgE;E2BlFhE,0B3BgFqE;C2B/EtE;;AAGD;;EAEE,e3B4EgE;C2BhEjE;;AzCDC;;;EyCRE,e3ByE8D;E2BxE9D,0BAAyC;CzCU1C;;AyChBH;;EAUI,YAAW;EACX,0B3BmE8D;E2BlE9D,sB3BkE8D;C2BjE/D;;AAnBH;EACE,e3BmFgE;E2BlFhE,0B3BgFqE;C2B/EtE;;AAGD;;EAEE,e3B4EgE;C2BhEjE;;AzCDC;;;EyCRE,e3ByE8D;E2BxE9D,0BAAyC;CzCU1C;;AyChBH;;EAUI,YAAW;EACX,0B3BmE8D;E2BlE9D,sB3BkE8D;C2BjE/D;;AAnBH;EACE,e3BmFgE;E2BlFhE,0B3BgFqE;C2B/EtE;;AAGD;;EAEE,e3B4EgE;C2BhEjE;;AzCDC;;;EyCRE,e3ByE8D;E2BxE9D,0BAAyC;CzCU1C;;AyChBH;;EAUI,YAAW;EACX,0B3BmE8D;E2BlE9D,sB3BkE8D;C2BjE/D;;ACtBL;EACE,aAAY;EACZ,kB3CizBiD;E2ChzBjD,kB3C+OqB;E2C9OrB,eAAc;EACd,Y3CuDW;E2CtDX,0B3C4CW;E2C3CX,YAAW;CAOZ;;A1CQG;E0CZA,Y3CkDS;E2CjDT,sBAAqB;EACrB,aAAY;C1CaX;;A0CHL;EACE,WAAU;EACV,wBAAuB;EACvB,UAAS;EACT,yBAAwB;CACzB;;ACpBD;EACE,iBAAgB;CACjB;;AAGD;EACE,gBAAe;EACf,OAAM;EACN,SAAQ;EACR,UAAS;EACT,QAAO;EACP,c5C0f8B;E4Czf9B,cAAa;EACb,iBAAgB;EAGhB,WAAU;CAWX;;AAtBD;ErCPM,4CPqsB8C;EOrsB9C,oCPqsB8C;EOrsB9C,qEPqsB8C;E4C3qBhD,sCAA6B;UAA7B,8BAA6B;CAC9B;;AApBH;EAqByB,mCAA0B;UAA1B,2BAA0B;CAAI;;AAEvD;EACE,mBAAkB;EAClB,iBAAgB;CACjB;;AAGD;EACE,mBAAkB;EAClB,YAAW;EACX,a5CuoBgC;C4CtoBjC;;AAGD;EACE,mBAAkB;EAClB,qBAAa;EAAb,cAAa;EACb,2BAAsB;MAAtB,uBAAsB;EACtB,uB5CFW;E4CGX,6BAA4B;EAC5B,qC5CMW;EMxDT,sBNoN0B;E4C9J5B,WAAU;CACX;;AAGD;EACE,gBAAe;EACf,OAAM;EACN,SAAQ;EACR,UAAS;EACT,QAAO;EACP,c5Cuc8B;E4Ctc9B,uB5CTW;C4CcZ;;AAZD;EAUW,WAAU;CAAK;;AAV1B;EAWW,a5CsnBqB;C4CtnBe;;AAK/C;EACE,qBAAa;EAAb,cAAa;EACb,uBAAmB;MAAnB,oBAAmB;EACnB,uBAA8B;MAA9B,+BAA8B;EAC9B,c5CknBgC;E4CjnBhC,iC5C/BgB;C4CgCjB;;AAGD;EACE,iBAAgB;EAChB,iB5C4JoB;C4C3JrB;;AAID;EACE,mBAAkB;EAGlB,mBAAc;MAAd,eAAc;EACd,c5C8kBgC;C4C7kBjC;;AAGD;EACE,qBAAa;EAAb,cAAa;EACb,uBAAmB;MAAnB,oBAAmB;EACnB,mBAAyB;MAAzB,0BAAyB;EACzB,c5CskBgC;E4CrkBhC,8B5CxDgB;C4C6DjB;;AAVD;EAQyB,oBAAmB;CAAK;;AARjD;EASwB,qBAAoB;CAAK;;AAIjD;EACE,mBAAkB;EAClB,aAAY;EACZ,YAAW;EACX,aAAY;EACZ,iBAAgB;CACjB;;AjClEG;EiCuEF;IACE,iB5CukB+B;I4CtkB/B,kBAAyC;GAC1C;EAMD;IAAY,iB5CgkBqB;G4ChkBG;C9CgtIrC;;AahyIG;EiCoFF;IAAY,iB5C0jBqB;G4C1jBG;C9CktIrC;;A+C71ID;EACE,mBAAkB;EAClB,c7C2gB8B;E6C1gB9B,eAAc;EACd,U7CynB6B;E8C5nB7B,wG9CuOiH;E8CrOjH,mBAAkB;EAClB,oB9C4OyB;E8C3OzB,iB9C+OoB;E8C9OpB,iBAAgB;EAChB,kBAAiB;EACjB,sBAAqB;EACrB,kBAAiB;EACjB,qBAAoB;EACpB,uBAAsB;EACtB,mBAAkB;EAClB,qBAAoB;EACpB,oBAAmB;EACnB,iBAAgB;EDPhB,oB7CsOsB;E6CpOtB,sBAAqB;EACrB,WAAU;CAoFX;;AA/FD;EAaW,a7C6mBqB;C6C7mBQ;;AAbxC;EAgBI,mBAAkB;EAClB,eAAc;EACd,W7C8mB6B;E6C7mB7B,Y7C8mB6B;C6C7mB9B;;AApBH;EAuBI,eAA+B;CAWhC;;AAlCH;EAyBM,UAAS;CACV;;AA1BL;EA6BM,kBAAuC;EACvC,YAAW;EACX,wBAAyD;EACzD,uB7C2BO;C6C1BR;;AAjCL;EAoCI,e7C4lB6B;C6CjlB9B;;AA/CH;EAsCM,QAAO;CACR;;AAvCL;EA0CM,iBAAsC;EACtC,YAAW;EACX,4BAA8E;EAC9E,yB7CcO;C6CbR;;AA9CL;EAiDI,eAA+B;CAWhC;;AA5DH;EAmDM,OAAM;CACP;;AApDL;EAuDM,kBAAuC;EACvC,YAAW;EACX,wB7CukB2B;E6CtkB3B,0B7CCO;C6CAR;;AA3DL;EA8DI,e7CkkB6B;C6CtjB9B;;AA1EH;EAgEM,SAAQ;CACT;;AAjEL;EAoEM,SAAQ;EACR,iBAAsC;EACtC,YAAW;EACX,4B7CyjB2B;E6CxjB3B,wB7CbO;C6CcR;;AAzEL;EA2FI,mBAAkB;EAClB,0BAAyB;EACzB,oBAAmB;CACpB;;AAIH;EACE,iB7CohBiC;E6CnhBjC,iB7CwhB+B;E6CvhB/B,Y7CpDW;E6CqDX,mBAAkB;EAClB,uB7C5CW;EMxDT,uBNmN2B;C6C7G9B;;AE1GD;EACE,mBAAkB;EAClB,OAAM;EACN,QAAO;EACP,c/CygB8B;E+CxgB9B,eAAc;EACd,iB/CooByC;E+CnoBzC,a/CioBuC;E8CtoBvC,wG9CuOiH;E8CrOjH,mBAAkB;EAClB,oB9C4OyB;E8C3OzB,iB9C+OoB;E8C9OpB,iBAAgB;EAChB,kBAAiB;EACjB,sBAAqB;EACrB,kBAAiB;EACjB,qBAAoB;EACpB,uBAAsB;EACtB,mBAAkB;EAClB,qBAAoB;EACpB,oBAAmB;EACnB,iBAAgB;ECLhB,oB/CoOsB;E+ClOtB,sBAAqB;EACrB,uB/CoCW;E+CnCX,6BAA4B;EAC5B,qC/C4CW;EMxDT,sBNoN0B;C+C5C7B;;AA5KD;EAyBI,mBAAkB;EAClB,eAAc;EACd,Y/C6nBsC;E+C5nBtC,Y/C6nBqC;C+C5nBtC;;AA7BH;;EAiCI,mBAAkB;EAClB,eAAc;EACd,0BAAyB;EACzB,oBAAmB;CACpB;;AArCH;EAwCI,YAAW;EACX,mB/CmnB8D;C+ClnB/D;;AA1CH;EA4CI,YAAW;EACX,mB/C+mB8D;C+C9mB/D;;AA9CH;EAmDI,oB/CqmBsC;C+C/kBvC;;AAzEH;EAsDM,UAAS;CACV;;AAvDL;;EA2DM,uBAAsB;CACvB;;AA5DL;EA+DM,c/C6lB4D;E+C5lB5D,kBAA6C;EAC7C,sC/C4lBmE;C+C3lBpE;;AAlEL;EAqEM,cAAwC;EACxC,kBAA6C;EAC7C,uB/CrBO;C+CsBR;;AAxEL;EA4EI,kB/C4kBsC;C+CvjBvC;;AAjGH;EA+EM,QAAO;CACR;;AAhFL;;EAoFM,iBAA4C;EAC5C,qBAAoB;CACrB;;AAtFL;EAyFM,Y/CmkB4D;E+ClkB5D,wC/CmkBmE;C+ClkBpE;;AA3FL;EA8FM,YAAsC;EACtC,yB/C7CO;C+C8CR;;AAhGL;EAoGI,iB/CojBsC;C+CnhBvC;;AArIH;EAuGM,OAAM;CACP;;AAxGL;;EA4GM,kBAAuC;EACvC,oBAAmB;CACpB;;AA9GL;EAiHM,W/C2iB4D;E+C1iB5D,yC/C2iBmE;C+C1iBpE;;AAnHL;EAsHM,WAAqC;EACrC,0B/CrEO;C+CsER;;AAxHL;EA4HM,mBAAkB;EAClB,OAAM;EACN,UAAS;EACT,eAAc;EACd,YAAW;EACX,mBAAkB;EAClB,YAAW;EACX,iC/C4gBwD;C+C3gBzD;;AApIL;EAwII,mB/CghBsC;C+C3fvC;;AA7JH;EA2IM,SAAQ;CACT;;AA5IL;;EAgJM,iBAA4C;EAC5C,sBAAqB;CACtB;;AAlJL;EAqJM,a/CugB4D;E+CtgB5D,uC/CugBmE;C+CtgBpE;;AAvJL;EA0JM,aAAuC;EACvC,wB/CzGO;C+C0GR;;AAoBL;EACE,kB/CieyC;E+ChezC,iBAAgB;EAChB,gB/C0DmB;E+CzDnB,e/C8E8B;E+C7E9B,0B/C0d4D;E+Czd5D,iCAAyE;EzC5KvE,2CyC6KyE;EzC5KzE,4CyC4KyE;CAM5E;;AAbD;EAWI,cAAa;CACd;;AAGH;EACE,kB/CsdqC;E+CrdrC,e/CtIgB;C+CuIjB;;ACjMD;EACE,mBAAkB;CACnB;;AAED;EACE,mBAAkB;EAClB,YAAW;EACX,iBAAgB;CACjB;;AAED;EACE,mBAAkB;EAClB,cAAa;EACb,uBAAmB;MAAnB,oBAAmB;EACnB,YAAW;EzCVP,wCPyyB4C;EOzyB5C,gCPyyB4C;EOzyB5C,6DPyyB4C;EgD7xBhD,oCAA2B;UAA3B,4BAA2B;EAC3B,4BAAmB;UAAnB,oBAAmB;CACpB;;AAED;;;EAGE,eAAc;CACf;;AAED;;EAEE,mBAAkB;EAClB,OAAM;CACP;;AAGD;;EAEE,iCAAwB;UAAxB,yBAAwB;CAKzB;;AAHyC;EAJ1C;;IAKI,wCAA+B;YAA/B,gCAA+B;GAElC;ClDuoJA;;AkDroJD;;EAEE,oCAA2B;UAA3B,4BAA2B;CAK5B;;AAHyC;EAJ1C;;IAKI,2CAAkC;YAAlC,mCAAkC;GAErC;ClD0oJA;;AkDxoJD;;EAEE,qCAA4B;UAA5B,6BAA4B;CAK7B;;AAHyC;EAJ1C;;IAKI,4CAAmC;YAAnC,oCAAmC;GAEtC;ClD6oJA;;AkDtoJD;;EAEE,mBAAkB;EAClB,OAAM;EACN,UAAS;EAET,qBAAa;EAAb,cAAa;EACb,uBAAmB;MAAnB,oBAAmB;EACnB,sBAAuB;MAAvB,wBAAuB;EACvB,WhDmtB+C;EgDltB/C,YhD1BW;EgD2BX,mBAAkB;EAClB,ahDitB8C;CgDtsB/C;;A/CnEG;;;E+C8DA,YhDlCS;EgDmCT,sBAAqB;EACrB,WAAU;EACV,YAAW;C/C9DV;;A+CiEL;EACE,QAAO;CACR;;AACD;EACE,SAAQ;CACT;;AAGD;;EAEE,sBAAqB;EACrB,YhDosBgD;EgDnsBhD,ahDmsBgD;EgDlsBhD,gDAA+C;EAC/C,2BAA0B;CAC3B;;AACD;EACE,8MjC/DyI;CiCgE1I;;AACD;EACE,gNjClEyI;CiCmE1I;;AAQD;EACE,mBAAkB;EAClB,SAAQ;EACR,aAAY;EACZ,QAAO;EACP,YAAW;EACX,qBAAa;EAAb,cAAa;EACb,sBAAuB;MAAvB,wBAAuB;EACvB,gBAAe;EAEf,kBhD6pB+C;EgD5pB/C,iBhD4pB+C;EgD3pB/C,iBAAgB;CAoCjB;;AAhDD;EAeI,mBAAkB;EAClB,mBAAc;MAAd,eAAc;EACd,YhDypB8C;EgDxpB9C,YhDypB6C;EgDxpB7C,kBhDypB6C;EgDxpB7C,iBhDwpB6C;EgDvpB7C,oBAAmB;EACnB,2ChD3FS;CgDgHV;;AA3CH;EA0BM,mBAAkB;EAClB,WAAU;EACV,QAAO;EACP,sBAAqB;EACrB,YAAW;EACX,aAAY;EACZ,YAAW;CACZ;;AAjCL;EAmCM,mBAAkB;EAClB,cAAa;EACb,QAAO;EACP,sBAAqB;EACrB,YAAW;EACX,aAAY;EACZ,YAAW;CACZ;;AA1CL;EA8CI,uBhDnHS;CgDoHV;;AAQH;EACE,mBAAkB;EAClB,WAA6C;EAC7C,aAAY;EACZ,UAA4C;EAC5C,YAAW;EACX,kBAAiB;EACjB,qBAAoB;EACpB,YhDpIW;EgDqIX,mBAAkB;CACnB;;ACxLD;EAAqB,oCAAmC;CAAK;;AAC7D;EAAqB,+BAA8B;CAAK;;AACxD;EAAqB,kCAAiC;CAAK;;AAC3D;EAAqB,kCAAiC;CAAK;;AAC3D;EAAqB,uCAAsC;CAAK;;AAChE;EAAqB,oCAAmC;CAAK;;ACF3D;EACE,qCAAmC;CACpC;;AjDiBC;EiDdE,qCAAgD;CjDiBjD;;AiDtBH;EACE,qCAAmC;CACpC;;AjDiBC;EiDdE,qCAAgD;CjDiBjD;;AiDtBH;EACE,qCAAmC;CACpC;;AjDiBC;EiDdE,qCAAgD;CjDiBjD;;AiDtBH;EACE,qCAAmC;CACpC;;AjDiBC;EiDdE,qCAAgD;CjDiBjD;;AiDtBH;EACE,qCAAmC;CACpC;;AjDiBC;EiDdE,qCAAgD;CjDiBjD;;AiDtBH;EACE,qCAAmC;CACpC;;AjDiBC;EiDdE,qCAAgD;CjDiBjD;;AiDtBH;EACE,qCAAmC;CACpC;;AjDiBC;EiDdE,qCAAgD;CjDiBjD;;AiDtBH;EACE,qCAAmC;CACpC;;AjDiBC;EiDdE,qCAAgD;CjDiBjD;;AkDrBL;EAAkB,yCAAwC;CAAK;;ACA/D;EAAmB,qCAAsC;CAAI;;AAC7D;EAAmB,qBAAoB;CAAK;;AAC5C;EAAmB,yBAAwB;CAAK;;AAChD;EAAmB,2BAA0B;CAAK;;AAClD;EAAmB,4BAA2B;CAAK;;AACnD;EAAmB,0BAAyB;CAAK;;AAG/C;EACE,iCAA+B;CAChC;;AAFD;EACE,iCAA+B;CAChC;;AAFD;EACE,iCAA+B;CAChC;;AAFD;EACE,iCAA+B;CAChC;;AAFD;EACE,iCAA+B;CAChC;;AAFD;EACE,iCAA+B;CAChC;;AAFD;EACE,iCAA+B;CAChC;;AAFD;EACE,iCAA+B;CAChC;;AAOH;EACE,kCAAwC;CACzC;;AACD;EACE,2CAAiD;EACjD,4CAAkD;CACnD;;AACD;EACE,4CAAkD;EAClD,+CAAqD;CACtD;;AACD;EACE,+CAAqD;EACrD,8CAAoD;CACrD;;AACD;EACE,2CAAiD;EACjD,8CAAoD;CACrD;;AAED;EACE,mBAAkB;CACnB;;AAED;EACE,iBAAgB;CACjB;;AtB9CC;EACE,eAAc;EACd,YAAW;EACX,YAAW;CACZ;;AuBGC;EAA2B,yBAAwB;CAAK;;AACxD;EAA2B,2BAA0B;CAAK;;AAC1D;EAA2B,iCAAgC;CAAK;;AAChE;EAA2B,0BAAyB;CAAK;;AACzD;EAA2B,0BAAyB;CAAK;;AACzD;EAA2B,+BAA8B;CAAK;;AAC9D;EAA2B,gCAAwB;EAAxB,yBAAwB;CAAK;;AACxD;EAA2B,uCAA+B;EAA/B,gCAA+B;CAAK;;A1CyC/D;E0ChDA;IAA2B,yBAAwB;GAAK;EACxD;IAA2B,2BAA0B;GAAK;EAC1D;IAA2B,iCAAgC;GAAK;EAChE;IAA2B,0BAAyB;GAAK;EACzD;IAA2B,0BAAyB;GAAK;EACzD;IAA2B,+BAA8B;GAAK;EAC9D;IAA2B,gCAAwB;IAAxB,yBAAwB;GAAK;EACxD;IAA2B,uCAA+B;IAA/B,gCAA+B;GAAK;CvD2hKlE;;Aal/JG;E0ChDA;IAA2B,yBAAwB;GAAK;EACxD;IAA2B,2BAA0B;GAAK;EAC1D;IAA2B,iCAAgC;GAAK;EAChE;IAA2B,0BAAyB;GAAK;EACzD;IAA2B,0BAAyB;GAAK;EACzD;IAA2B,+BAA8B;GAAK;EAC9D;IAA2B,gCAAwB;IAAxB,yBAAwB;GAAK;EACxD;IAA2B,uCAA+B;IAA/B,gCAA+B;GAAK;CvDsjKlE;;Aa7gKG;E0ChDA;IAA2B,yBAAwB;GAAK;EACxD;IAA2B,2BAA0B;GAAK;EAC1D;IAA2B,iCAAgC;GAAK;EAChE;IAA2B,0BAAyB;GAAK;EACzD;IAA2B,0BAAyB;GAAK;EACzD;IAA2B,+BAA8B;GAAK;EAC9D;IAA2B,gCAAwB;IAAxB,yBAAwB;GAAK;EACxD;IAA2B,uCAA+B;IAA/B,gCAA+B;GAAK;CvDilKlE;;AaxiKG;E0ChDA;IAA2B,yBAAwB;GAAK;EACxD;IAA2B,2BAA0B;GAAK;EAC1D;IAA2B,iCAAgC;GAAK;EAChE;IAA2B,0BAAyB;GAAK;EACzD;IAA2B,0BAAyB;GAAK;EACzD;IAA2B,+BAA8B;GAAK;EAC9D;IAA2B,gCAAwB;IAAxB,yBAAwB;GAAK;EACxD;IAA2B,uCAA+B;IAA/B,gCAA+B;GAAK;CvD4mKlE;;AuDnmKD;EACE,yBAAwB;CAKzB;;AAHC;EAHF;IAII,0BAAyB;GAE5B;CvDumKA;;AuDrmKD;EACE,yBAAwB;CAKzB;;AAHC;EAHF;IAII,2BAA0B;GAE7B;CvDymKA;;AuDvmKD;EACE,yBAAwB;CAKzB;;AAHC;EAHF;IAII,iCAAgC;GAEnC;CvD2mKA;;AuDxmKC;EADF;IAEI,yBAAwB;GAE3B;CvD2mKA;;AwD7pKD;EACE,mBAAkB;EAClB,eAAc;EACd,YAAW;EACX,WAAU;EACV,iBAAgB;CAoBjB;;AAzBD;EAQI,eAAc;EACd,YAAW;CACZ;;AAVH;;;;;EAiBI,mBAAkB;EAClB,OAAM;EACN,UAAS;EACT,QAAO;EACP,YAAW;EACX,aAAY;EACZ,UAAS;CACV;;AAGH;EAEI,wBAA+B;CAChC;;AAGH;EAEI,oBAA+B;CAChC;;AAGH;EAEI,iBAA8B;CAC/B;;AAGH;EAEI,kBAA8B;CAC/B;;AC1CC;EAAgC,mCAA8B;MAA9B,+BAA8B;CAAK;;AACnE;EAAgC,sCAAiC;MAAjC,kCAAiC;CAAK;;AACtE;EAAgC,2CAAsC;MAAtC,uCAAsC;CAAK;;AAC3E;EAAgC,8CAAyC;MAAzC,0CAAyC;CAAK;;AAE9E;EAA8B,+BAA0B;MAA1B,2BAA0B;CAAK;;AAC7D;EAA8B,iCAA4B;MAA5B,6BAA4B;CAAK;;AAC/D;EAA8B,uCAAkC;MAAlC,mCAAkC;CAAK;;AAErE;EAAoC,gCAAsC;MAAtC,uCAAsC;CAAK;;AAC/E;EAAoC,8BAAoC;MAApC,qCAAoC;CAAK;;AAC7E;EAAoC,iCAAkC;MAAlC,mCAAkC;CAAK;;AAC3E;EAAoC,kCAAyC;MAAzC,0CAAyC;CAAK;;AAClF;EAAoC,qCAAwC;MAAxC,yCAAwC;CAAK;;AAEjF;EAAiC,iCAAkC;MAAlC,mCAAkC;CAAK;;AACxE;EAAiC,+BAAgC;MAAhC,iCAAgC;CAAK;;AACtE;EAAiC,kCAA8B;MAA9B,+BAA8B;CAAK;;AACpE;EAAiC,oCAAgC;MAAhC,iCAAgC;CAAK;;AACtE;EAAiC,mCAA+B;MAA/B,gCAA+B;CAAK;;AAErE;EAAkC,qCAAoC;MAApC,qCAAoC;CAAK;;AAC3E;EAAkC,mCAAkC;MAAlC,mCAAkC;CAAK;;AACzE;EAAkC,sCAAgC;MAAhC,iCAAgC;CAAK;;AACvE;EAAkC,uCAAuC;MAAvC,wCAAuC;CAAK;;AAC9E;EAAkC,0CAAsC;MAAtC,uCAAsC;CAAK;;AAC7E;EAAkC,uCAAiC;MAAjC,kCAAiC;CAAK;;AAExE;EAAgC,qCAA2B;MAA3B,4BAA2B;CAAK;;AAChE;EAAgC,sCAAiC;MAAjC,kCAAiC;CAAK;;AACtE;EAAgC,oCAA+B;MAA/B,gCAA+B;CAAK;;AACpE;EAAgC,uCAA6B;MAA7B,8BAA6B;CAAK;;AAClE;EAAgC,yCAA+B;MAA/B,gCAA+B;CAAK;;AACpE;EAAgC,wCAA8B;MAA9B,+BAA8B;CAAK;;A5CenE;E4ChDA;IAAgC,mCAA8B;QAA9B,+BAA8B;GAAK;EACnE;IAAgC,sCAAiC;QAAjC,kCAAiC;GAAK;EACtE;IAAgC,2CAAsC;QAAtC,uCAAsC;GAAK;EAC3E;IAAgC,8CAAyC;QAAzC,0CAAyC;GAAK;EAE9E;IAA8B,+BAA0B;QAA1B,2BAA0B;GAAK;EAC7D;IAA8B,iCAA4B;QAA5B,6BAA4B;GAAK;EAC/D;IAA8B,uCAAkC;QAAlC,mCAAkC;GAAK;EAErE;IAAoC,gCAAsC;QAAtC,uCAAsC;GAAK;EAC/E;IAAoC,8BAAoC;QAApC,qCAAoC;GAAK;EAC7E;IAAoC,iCAAkC;QAAlC,mCAAkC;GAAK;EAC3E;IAAoC,kCAAyC;QAAzC,0CAAyC;GAAK;EAClF;IAAoC,qCAAwC;QAAxC,yCAAwC;GAAK;EAEjF;IAAiC,iCAAkC;QAAlC,mCAAkC;GAAK;EACxE;IAAiC,+BAAgC;QAAhC,iCAAgC;GAAK;EACtE;IAAiC,kCAA8B;QAA9B,+BAA8B;GAAK;EACpE;IAAiC,oCAAgC;QAAhC,iCAAgC;GAAK;EACtE;IAAiC,mCAA+B;QAA/B,gCAA+B;GAAK;EAErE;IAAkC,qCAAoC;QAApC,qCAAoC;GAAK;EAC3E;IAAkC,mCAAkC;QAAlC,mCAAkC;GAAK;EACzE;IAAkC,sCAAgC;QAAhC,iCAAgC;GAAK;EACvE;IAAkC,uCAAuC;QAAvC,wCAAuC;GAAK;EAC9E;IAAkC,0CAAsC;QAAtC,uCAAsC;GAAK;EAC7E;IAAkC,uCAAiC;QAAjC,kCAAiC;GAAK;EAExE;IAAgC,qCAA2B;QAA3B,4BAA2B;GAAK;EAChE;IAAgC,sCAAiC;QAAjC,kCAAiC;GAAK;EACtE;IAAgC,oCAA+B;QAA/B,gCAA+B;GAAK;EACpE;IAAgC,uCAA6B;QAA7B,8BAA6B;GAAK;EAClE;IAAgC,yCAA+B;QAA/B,gCAA+B;GAAK;EACpE;IAAgC,wCAA8B;QAA9B,+BAA8B;GAAK;CzD+2KtE;;Aah2KG;E4ChDA;IAAgC,mCAA8B;QAA9B,+BAA8B;GAAK;EACnE;IAAgC,sCAAiC;QAAjC,kCAAiC;GAAK;EACtE;IAAgC,2CAAsC;QAAtC,uCAAsC;GAAK;EAC3E;IAAgC,8CAAyC;QAAzC,0CAAyC;GAAK;EAE9E;IAA8B,+BAA0B;QAA1B,2BAA0B;GAAK;EAC7D;IAA8B,iCAA4B;QAA5B,6BAA4B;GAAK;EAC/D;IAA8B,uCAAkC;QAAlC,mCAAkC;GAAK;EAErE;IAAoC,gCAAsC;QAAtC,uCAAsC;GAAK;EAC/E;IAAoC,8BAAoC;QAApC,qCAAoC;GAAK;EAC7E;IAAoC,iCAAkC;QAAlC,mCAAkC;GAAK;EAC3E;IAAoC,kCAAyC;QAAzC,0CAAyC;GAAK;EAClF;IAAoC,qCAAwC;QAAxC,yCAAwC;GAAK;EAEjF;IAAiC,iCAAkC;QAAlC,mCAAkC;GAAK;EACxE;IAAiC,+BAAgC;QAAhC,iCAAgC;GAAK;EACtE;IAAiC,kCAA8B;QAA9B,+BAA8B;GAAK;EACpE;IAAiC,oCAAgC;QAAhC,iCAAgC;GAAK;EACtE;IAAiC,mCAA+B;QAA/B,gCAA+B;GAAK;EAErE;IAAkC,qCAAoC;QAApC,qCAAoC;GAAK;EAC3E;IAAkC,mCAAkC;QAAlC,mCAAkC;GAAK;EACzE;IAAkC,sCAAgC;QAAhC,iCAAgC;GAAK;EACvE;IAAkC,uCAAuC;QAAvC,wCAAuC;GAAK;EAC9E;IAAkC,0CAAsC;QAAtC,uCAAsC;GAAK;EAC7E;IAAkC,uCAAiC;QAAjC,kCAAiC;GAAK;EAExE;IAAgC,qCAA2B;QAA3B,4BAA2B;GAAK;EAChE;IAAgC,sCAAiC;QAAjC,kCAAiC;GAAK;EACtE;IAAgC,oCAA+B;QAA/B,gCAA+B;GAAK;EACpE;IAAgC,uCAA6B;QAA7B,8BAA6B;GAAK;EAClE;IAAgC,yCAA+B;QAA/B,gCAA+B;GAAK;EACpE;IAAgC,wCAA8B;QAA9B,+BAA8B;GAAK;CzDy8KtE;;Aa17KG;E4ChDA;IAAgC,mCAA8B;QAA9B,+BAA8B;GAAK;EACnE;IAAgC,sCAAiC;QAAjC,kCAAiC;GAAK;EACtE;IAAgC,2CAAsC;QAAtC,uCAAsC;GAAK;EAC3E;IAAgC,8CAAyC;QAAzC,0CAAyC;GAAK;EAE9E;IAA8B,+BAA0B;QAA1B,2BAA0B;GAAK;EAC7D;IAA8B,iCAA4B;QAA5B,6BAA4B;GAAK;EAC/D;IAA8B,uCAAkC;QAAlC,mCAAkC;GAAK;EAErE;IAAoC,gCAAsC;QAAtC,uCAAsC;GAAK;EAC/E;IAAoC,8BAAoC;QAApC,qCAAoC;GAAK;EAC7E;IAAoC,iCAAkC;QAAlC,mCAAkC;GAAK;EAC3E;IAAoC,kCAAyC;QAAzC,0CAAyC;GAAK;EAClF;IAAoC,qCAAwC;QAAxC,yCAAwC;GAAK;EAEjF;IAAiC,iCAAkC;QAAlC,mCAAkC;GAAK;EACxE;IAAiC,+BAAgC;QAAhC,iCAAgC;GAAK;EACtE;IAAiC,kCAA8B;QAA9B,+BAA8B;GAAK;EACpE;IAAiC,oCAAgC;QAAhC,iCAAgC;GAAK;EACtE;IAAiC,mCAA+B;QAA/B,gCAA+B;GAAK;EAErE;IAAkC,qCAAoC;QAApC,qCAAoC;GAAK;EAC3E;IAAkC,mCAAkC;QAAlC,mCAAkC;GAAK;EACzE;IAAkC,sCAAgC;QAAhC,iCAAgC;GAAK;EACvE;IAAkC,uCAAuC;QAAvC,wCAAuC;GAAK;EAC9E;IAAkC,0CAAsC;QAAtC,uCAAsC;GAAK;EAC7E;IAAkC,uCAAiC;QAAjC,kCAAiC;GAAK;EAExE;IAAgC,qCAA2B;QAA3B,4BAA2B;GAAK;EAChE;IAAgC,sCAAiC;QAAjC,kCAAiC;GAAK;EACtE;IAAgC,oCAA+B;QAA/B,gCAA+B;GAAK;EACpE;IAAgC,uCAA6B;QAA7B,8BAA6B;GAAK;EAClE;IAAgC,yCAA+B;QAA/B,gCAA+B;GAAK;EACpE;IAAgC,wCAA8B;QAA9B,+BAA8B;GAAK;CzDmiLtE;;AaphLG;E4ChDA;IAAgC,mCAA8B;QAA9B,+BAA8B;GAAK;EACnE;IAAgC,sCAAiC;QAAjC,kCAAiC;GAAK;EACtE;IAAgC,2CAAsC;QAAtC,uCAAsC;GAAK;EAC3E;IAAgC,8CAAyC;QAAzC,0CAAyC;GAAK;EAE9E;IAA8B,+BAA0B;QAA1B,2BAA0B;GAAK;EAC7D;IAA8B,iCAA4B;QAA5B,6BAA4B;GAAK;EAC/D;IAA8B,uCAAkC;QAAlC,mCAAkC;GAAK;EAErE;IAAoC,gCAAsC;QAAtC,uCAAsC;GAAK;EAC/E;IAAoC,8BAAoC;QAApC,qCAAoC;GAAK;EAC7E;IAAoC,iCAAkC;QAAlC,mCAAkC;GAAK;EAC3E;IAAoC,kCAAyC;QAAzC,0CAAyC;GAAK;EAClF;IAAoC,qCAAwC;QAAxC,yCAAwC;GAAK;EAEjF;IAAiC,iCAAkC;QAAlC,mCAAkC;GAAK;EACxE;IAAiC,+BAAgC;QAAhC,iCAAgC;GAAK;EACtE;IAAiC,kCAA8B;QAA9B,+BAA8B;GAAK;EACpE;IAAiC,oCAAgC;QAAhC,iCAAgC;GAAK;EACtE;IAAiC,mCAA+B;QAA/B,gCAA+B;GAAK;EAErE;IAAkC,qCAAoC;QAApC,qCAAoC;GAAK;EAC3E;IAAkC,mCAAkC;QAAlC,mCAAkC;GAAK;EACzE;IAAkC,sCAAgC;QAAhC,iCAAgC;GAAK;EACvE;IAAkC,uCAAuC;QAAvC,wCAAuC;GAAK;EAC9E;IAAkC,0CAAsC;QAAtC,uCAAsC;GAAK;EAC7E;IAAkC,uCAAiC;QAAjC,kCAAiC;GAAK;EAExE;IAAgC,qCAA2B;QAA3B,4BAA2B;GAAK;EAChE;IAAgC,sCAAiC;QAAjC,kCAAiC;GAAK;EACtE;IAAgC,oCAA+B;QAA/B,gCAA+B;GAAK;EACpE;IAAgC,uCAA6B;QAA7B,8BAA6B;GAAK;EAClE;IAAgC,yCAA+B;QAA/B,gCAA+B;GAAK;EACpE;IAAgC,wCAA8B;QAA9B,+BAA8B;GAAK;CzD6nLtE;;A0DlqLG;ECHF,uBAAsB;CDG2B;;AAC/C;ECDF,wBAAuB;CDC2B;;AAChD;ECCF,uBAAsB;CDD2B;;A7CkD/C;E6CpDA;ICHF,uBAAsB;GDG2B;EAC/C;ICDF,wBAAuB;GDC2B;EAChD;ICCF,uBAAsB;GDD2B;C1DwrLlD;;AatoLG;E6CpDA;ICHF,uBAAsB;GDG2B;EAC/C;ICDF,wBAAuB;GDC2B;EAChD;ICCF,uBAAsB;GDD2B;C1DosLlD;;AalpLG;E6CpDA;ICHF,uBAAsB;GDG2B;EAC/C;ICDF,wBAAuB;GDC2B;EAChD;ICCF,uBAAsB;GDD2B;C1DgtLlD;;Aa9pLG;E6CpDA;ICHF,uBAAsB;GDG2B;EAC/C;ICDF,wBAAuB;GDC2B;EAChD;ICCF,uBAAsB;GDD2B;C1D4tLlD;;A4DhuLD;EACE,gBAAe;EACf,OAAM;EACN,SAAQ;EACR,QAAO;EACP,c1DmgB8B;C0DlgB/B;;AAED;EACE,gBAAe;EACf,SAAQ;EACR,UAAS;EACT,QAAO;EACP,c1D2f8B;C0D1f/B;;AAG6B;EAD9B;IAEI,yBAAgB;IAAhB,iBAAgB;IAChB,OAAM;IACN,c1Dmf4B;G0Djf/B;C5DkuLA;;A6DtvLD;ECEE,mBAAkB;EAClB,WAAU;EACV,YAAW;EACX,WAAU;EACV,iBAAgB;EAChB,uBAAmB;EACnB,oBAAmB;EACnB,8BAAqB;UAArB,sBAAqB;EACrB,UAAS;CDRV;;ACkBC;EAEE,iBAAgB;EAChB,YAAW;EACX,aAAY;EACZ,kBAAiB;EACjB,WAAU;EACV,oBAAmB;EACnB,wBAAe;UAAf,gBAAe;CAChB;;AC7BC;EAAuB,sBAA4B;CAAI;;AAAvD;EAAuB,sBAA4B;CAAI;;AAAvD;EAAuB,sBAA4B;CAAI;;AAAvD;EAAuB,uBAA4B;CAAI;;AAAvD;EAAuB,uBAA4B;CAAI;;AAAvD;EAAuB,uBAA4B;CAAI;;AAAvD;EAAuB,uBAA4B;CAAI;;AAAvD;EAAuB,wBAA4B;CAAI;;AAI3D;EAAU,2BAA0B;CAAK;;AACzC;EAAU,4BAA2B;CAAK;;ACAlC;EAAiC,qBAAmC;CAAI;;AACxE;EAAiC,yBAAuC;CAAI;;AAC5E;EAAiC,2BAAyC;CAAI;;AAC9E;EAAiC,4BAA0C;CAAI;;AAC/E;EAAiC,0BAAwC;CAAI;;AAC7E;EACE,2BAAwC;EACxC,0BAAuC;CACxC;;AACD;EACE,yBAAuC;EACvC,4BAA0C;CAC3C;;AAZD;EAAiC,2BAAmC;CAAI;;AACxE;EAAiC,+BAAuC;CAAI;;AAC5E;EAAiC,iCAAyC;CAAI;;AAC9E;EAAiC,kCAA0C;CAAI;;AAC/E;EAAiC,gCAAwC;CAAI;;AAC7E;EACE,iCAAwC;EACxC,gCAAuC;CACxC;;AACD;EACE,+BAAuC;EACvC,kCAA0C;CAC3C;;AAZD;EAAiC,0BAAmC;CAAI;;AACxE;EAAiC,8BAAuC;CAAI;;AAC5E;EAAiC,gCAAyC;CAAI;;AAC9E;EAAiC,iCAA0C;CAAI;;AAC/E;EAAiC,+BAAwC;CAAI;;AAC7E;EACE,gCAAwC;EACxC,+BAAuC;CACxC;;AACD;EACE,8BAAuC;EACvC,iCAA0C;CAC3C;;AAZD;EAAiC,wBAAmC;CAAI;;AACxE;EAAiC,4BAAuC;CAAI;;AAC5E;EAAiC,8BAAyC;CAAI;;AAC9E;EAAiC,+BAA0C;CAAI;;AAC/E;EAAiC,6BAAwC;CAAI;;AAC7E;EACE,8BAAwC;EACxC,6BAAuC;CACxC;;AACD;EACE,4BAAuC;EACvC,+BAA0C;CAC3C;;AAZD;EAAiC,0BAAmC;CAAI;;AACxE;EAAiC,8BAAuC;CAAI;;AAC5E;EAAiC,gCAAyC;CAAI;;AAC9E;EAAiC,iCAA0C;CAAI;;AAC/E;EAAiC,+BAAwC;CAAI;;AAC7E;EACE,gCAAwC;EACxC,+BAAuC;CACxC;;AACD;EACE,8BAAuC;EACvC,iCAA0C;CAC3C;;AAZD;EAAiC,wBAAmC;CAAI;;AACxE;EAAiC,4BAAuC;CAAI;;AAC5E;EAAiC,8BAAyC;CAAI;;AAC9E;EAAiC,+BAA0C;CAAI;;AAC/E;EAAiC,6BAAwC;CAAI;;AAC7E;EACE,8BAAwC;EACxC,6BAAuC;CACxC;;AACD;EACE,4BAAuC;EACvC,+BAA0C;CAC3C;;AAZD;EAAiC,sBAAmC;CAAI;;AACxE;EAAiC,0BAAuC;CAAI;;AAC5E;EAAiC,4BAAyC;CAAI;;AAC9E;EAAiC,6BAA0C;CAAI;;AAC/E;EAAiC,2BAAwC;CAAI;;AAC7E;EACE,4BAAwC;EACxC,2BAAuC;CACxC;;AACD;EACE,0BAAuC;EACvC,6BAA0C;CAC3C;;AAZD;EAAiC,4BAAmC;CAAI;;AACxE;EAAiC,gCAAuC;CAAI;;AAC5E;EAAiC,kCAAyC;CAAI;;AAC9E;EAAiC,mCAA0C;CAAI;;AAC/E;EAAiC,iCAAwC;CAAI;;AAC7E;EACE,kCAAwC;EACxC,iCAAuC;CACxC;;AACD;EACE,gCAAuC;EACvC,mCAA0C;CAC3C;;AAZD;EAAiC,2BAAmC;CAAI;;AACxE;EAAiC,+BAAuC;CAAI;;AAC5E;EAAiC,iCAAyC;CAAI;;AAC9E;EAAiC,kCAA0C;CAAI;;AAC/E;EAAiC,gCAAwC;CAAI;;AAC7E;EACE,iCAAwC;EACxC,gCAAuC;CACxC;;AACD;EACE,+BAAuC;EACvC,kCAA0C;CAC3C;;AAZD;EAAiC,yBAAmC;CAAI;;AACxE;EAAiC,6BAAuC;CAAI;;AAC5E;EAAiC,+BAAyC;CAAI;;AAC9E;EAAiC,gCAA0C;CAAI;;AAC/E;EAAiC,8BAAwC;CAAI;;AAC7E;EACE,+BAAwC;EACxC,8BAAuC;CACxC;;AACD;EACE,6BAAuC;EACvC,gCAA0C;CAC3C;;AAZD;EAAiC,2BAAmC;CAAI;;AACxE;EAAiC,+BAAuC;CAAI;;AAC5E;EAAiC,iCAAyC;CAAI;;AAC9E;EAAiC,kCAA0C;CAAI;;AAC/E;EAAiC,gCAAwC;CAAI;;AAC7E;EACE,iCAAwC;EACxC,gCAAuC;CACxC;;AACD;EACE,+BAAuC;EACvC,kCAA0C;CAC3C;;AAZD;EAAiC,yBAAmC;CAAI;;AACxE;EAAiC,6BAAuC;CAAI;;AAC5E;EAAiC,+BAAyC;CAAI;;AAC9E;EAAiC,gCAA0C;CAAI;;AAC/E;EAAiC,8BAAwC;CAAI;;AAC7E;EACE,+BAAwC;EACxC,8BAAuC;CACxC;;AACD;EACE,6BAAuC;EACvC,gCAA0C;CAC3C;;AAKL;EAAoB,wBAA8B;CAAK;;AACvD;EAAoB,4BAA8B;CAAK;;AACvD;EAAoB,8BAA8B;CAAK;;AACvD;EAAoB,+BAA8B;CAAK;;AACvD;EAAoB,6BAA8B;CAAK;;AACvD;EACE,8BAA6B;EAC7B,6BAA6B;CAC9B;;AACD;EACE,4BAA8B;EAC9B,+BAA8B;CAC/B;;AnDkBD;EmD/CI;IAAiC,qBAAmC;GAAI;EACxE;IAAiC,yBAAuC;GAAI;EAC5E;IAAiC,2BAAyC;GAAI;EAC9E;IAAiC,4BAA0C;GAAI;EAC/E;IAAiC,0BAAwC;GAAI;EAC7E;IACE,2BAAwC;IACxC,0BAAuC;GACxC;EACD;IACE,yBAAuC;IACvC,4BAA0C;GAC3C;EAZD;IAAiC,2BAAmC;GAAI;EACxE;IAAiC,+BAAuC;GAAI;EAC5E;IAAiC,iCAAyC;GAAI;EAC9E;IAAiC,kCAA0C;GAAI;EAC/E;IAAiC,gCAAwC;GAAI;EAC7E;IACE,iCAAwC;IACxC,gCAAuC;GACxC;EACD;IACE,+BAAuC;IACvC,kCAA0C;GAC3C;EAZD;IAAiC,0BAAmC;GAAI;EACxE;IAAiC,8BAAuC;GAAI;EAC5E;IAAiC,gCAAyC;GAAI;EAC9E;IAAiC,iCAA0C;GAAI;EAC/E;IAAiC,+BAAwC;GAAI;EAC7E;IACE,gCAAwC;IACxC,+BAAuC;GACxC;EACD;IACE,8BAAuC;IACvC,iCAA0C;GAC3C;EAZD;IAAiC,wBAAmC;GAAI;EACxE;IAAiC,4BAAuC;GAAI;EAC5E;IAAiC,8BAAyC;GAAI;EAC9E;IAAiC,+BAA0C;GAAI;EAC/E;IAAiC,6BAAwC;GAAI;EAC7E;IACE,8BAAwC;IACxC,6BAAuC;GACxC;EACD;IACE,4BAAuC;IACvC,+BAA0C;GAC3C;EAZD;IAAiC,0BAAmC;GAAI;EACxE;IAAiC,8BAAuC;GAAI;EAC5E;IAAiC,gCAAyC;GAAI;EAC9E;IAAiC,iCAA0C;GAAI;EAC/E;IAAiC,+BAAwC;GAAI;EAC7E;IACE,gCAAwC;IACxC,+BAAuC;GACxC;EACD;IACE,8BAAuC;IACvC,iCAA0C;GAC3C;EAZD;IAAiC,wBAAmC;GAAI;EACxE;IAAiC,4BAAuC;GAAI;EAC5E;IAAiC,8BAAyC;GAAI;EAC9E;IAAiC,+BAA0C;GAAI;EAC/E;IAAiC,6BAAwC;GAAI;EAC7E;IACE,8BAAwC;IACxC,6BAAuC;GACxC;EACD;IACE,4BAAuC;IACvC,+BAA0C;GAC3C;EAZD;IAAiC,sBAAmC;GAAI;EACxE;IAAiC,0BAAuC;GAAI;EAC5E;IAAiC,4BAAyC;GAAI;EAC9E;IAAiC,6BAA0C;GAAI;EAC/E;IAAiC,2BAAwC;GAAI;EAC7E;IACE,4BAAwC;IACxC,2BAAuC;GACxC;EACD;IACE,0BAAuC;IACvC,6BAA0C;GAC3C;EAZD;IAAiC,4BAAmC;GAAI;EACxE;IAAiC,gCAAuC;GAAI;EAC5E;IAAiC,kCAAyC;GAAI;EAC9E;IAAiC,mCAA0C;GAAI;EAC/E;IAAiC,iCAAwC;GAAI;EAC7E;IACE,kCAAwC;IACxC,iCAAuC;GACxC;EACD;IACE,gCAAuC;IACvC,mCAA0C;GAC3C;EAZD;IAAiC,2BAAmC;GAAI;EACxE;IAAiC,+BAAuC;GAAI;EAC5E;IAAiC,iCAAyC;GAAI;EAC9E;IAAiC,kCAA0C;GAAI;EAC/E;IAAiC,gCAAwC;GAAI;EAC7E;IACE,iCAAwC;IACxC,gCAAuC;GACxC;EACD;IACE,+BAAuC;IACvC,kCAA0C;GAC3C;EAZD;IAAiC,yBAAmC;GAAI;EACxE;IAAiC,6BAAuC;GAAI;EAC5E;IAAiC,+BAAyC;GAAI;EAC9E;IAAiC,gCAA0C;GAAI;EAC/E;IAAiC,8BAAwC;GAAI;EAC7E;IACE,+BAAwC;IACxC,8BAAuC;GACxC;EACD;IACE,6BAAuC;IACvC,gCAA0C;GAC3C;EAZD;IAAiC,2BAAmC;GAAI;EACxE;IAAiC,+BAAuC;GAAI;EAC5E;IAAiC,iCAAyC;GAAI;EAC9E;IAAiC,kCAA0C;GAAI;EAC/E;IAAiC,gCAAwC;GAAI;EAC7E;IACE,iCAAwC;IACxC,gCAAuC;GACxC;EACD;IACE,+BAAuC;IACvC,kCAA0C;GAC3C;EAZD;IAAiC,yBAAmC;GAAI;EACxE;IAAiC,6BAAuC;GAAI;EAC5E;IAAiC,+BAAyC;GAAI;EAC9E;IAAiC,gCAA0C;GAAI;EAC/E;IAAiC,8BAAwC;GAAI;EAC7E;IACE,+BAAwC;IACxC,8BAAuC;GACxC;EACD;IACE,6BAAuC;IACvC,gCAA0C;GAC3C;EAKL;IAAoB,wBAA8B;GAAK;EACvD;IAAoB,4BAA8B;GAAK;EACvD;IAAoB,8BAA8B;GAAK;EACvD;IAAoB,+BAA8B;GAAK;EACvD;IAAoB,6BAA8B;GAAK;EACvD;IACE,8BAA6B;IAC7B,6BAA6B;GAC9B;EACD;IACE,4BAA8B;IAC9B,+BAA8B;GAC/B;ChEs8MJ;;Aap7MG;EmD/CI;IAAiC,qBAAmC;GAAI;EACxE;IAAiC,yBAAuC;GAAI;EAC5E;IAAiC,2BAAyC;GAAI;EAC9E;IAAiC,4BAA0C;GAAI;EAC/E;IAAiC,0BAAwC;GAAI;EAC7E;IACE,2BAAwC;IACxC,0BAAuC;GACxC;EACD;IACE,yBAAuC;IACvC,4BAA0C;GAC3C;EAZD;IAAiC,2BAAmC;GAAI;EACxE;IAAiC,+BAAuC;GAAI;EAC5E;IAAiC,iCAAyC;GAAI;EAC9E;IAAiC,kCAA0C;GAAI;EAC/E;IAAiC,gCAAwC;GAAI;EAC7E;IACE,iCAAwC;IACxC,gCAAuC;GACxC;EACD;IACE,+BAAuC;IACvC,kCAA0C;GAC3C;EAZD;IAAiC,0BAAmC;GAAI;EACxE;IAAiC,8BAAuC;GAAI;EAC5E;IAAiC,gCAAyC;GAAI;EAC9E;IAAiC,iCAA0C;GAAI;EAC/E;IAAiC,+BAAwC;GAAI;EAC7E;IACE,gCAAwC;IACxC,+BAAuC;GACxC;EACD;IACE,8BAAuC;IACvC,iCAA0C;GAC3C;EAZD;IAAiC,wBAAmC;GAAI;EACxE;IAAiC,4BAAuC;GAAI;EAC5E;IAAiC,8BAAyC;GAAI;EAC9E;IAAiC,+BAA0C;GAAI;EAC/E;IAAiC,6BAAwC;GAAI;EAC7E;IACE,8BAAwC;IACxC,6BAAuC;GACxC;EACD;IACE,4BAAuC;IACvC,+BAA0C;GAC3C;EAZD;IAAiC,0BAAmC;GAAI;EACxE;IAAiC,8BAAuC;GAAI;EAC5E;IAAiC,gCAAyC;GAAI;EAC9E;IAAiC,iCAA0C;GAAI;EAC/E;IAAiC,+BAAwC;GAAI;EAC7E;IACE,gCAAwC;IACxC,+BAAuC;GACxC;EACD;IACE,8BAAuC;IACvC,iCAA0C;GAC3C;EAZD;IAAiC,wBAAmC;GAAI;EACxE;IAAiC,4BAAuC;GAAI;EAC5E;IAAiC,8BAAyC;GAAI;EAC9E;IAAiC,+BAA0C;GAAI;EAC/E;IAAiC,6BAAwC;GAAI;EAC7E;IACE,8BAAwC;IACxC,6BAAuC;GACxC;EACD;IACE,4BAAuC;IACvC,+BAA0C;GAC3C;EAZD;IAAiC,sBAAmC;GAAI;EACxE;IAAiC,0BAAuC;GAAI;EAC5E;IAAiC,4BAAyC;GAAI;EAC9E;IAAiC,6BAA0C;GAAI;EAC/E;IAAiC,2BAAwC;GAAI;EAC7E;IACE,4BAAwC;IACxC,2BAAuC;GACxC;EACD;IACE,0BAAuC;IACvC,6BAA0C;GAC3C;EAZD;IAAiC,4BAAmC;GAAI;EACxE;IAAiC,gCAAuC;GAAI;EAC5E;IAAiC,kCAAyC;GAAI;EAC9E;IAAiC,mCAA0C;GAAI;EAC/E;IAAiC,iCAAwC;GAAI;EAC7E;IACE,kCAAwC;IACxC,iCAAuC;GACxC;EACD;IACE,gCAAuC;IACvC,mCAA0C;GAC3C;EAZD;IAAiC,2BAAmC;GAAI;EACxE;IAAiC,+BAAuC;GAAI;EAC5E;IAAiC,iCAAyC;GAAI;EAC9E;IAAiC,kCAA0C;GAAI;EAC/E;IAAiC,gCAAwC;GAAI;EAC7E;IACE,iCAAwC;IACxC,gCAAuC;GACxC;EACD;IACE,+BAAuC;IACvC,kCAA0C;GAC3C;EAZD;IAAiC,yBAAmC;GAAI;EACxE;IAAiC,6BAAuC;GAAI;EAC5E;IAAiC,+BAAyC;GAAI;EAC9E;IAAiC,gCAA0C;GAAI;EAC/E;IAAiC,8BAAwC;GAAI;EAC7E;IACE,+BAAwC;IACxC,8BAAuC;GACxC;EACD;IACE,6BAAuC;IACvC,gCAA0C;GAC3C;EAZD;IAAiC,2BAAmC;GAAI;EACxE;IAAiC,+BAAuC;GAAI;EAC5E;IAAiC,iCAAyC;GAAI;EAC9E;IAAiC,kCAA0C;GAAI;EAC/E;IAAiC,gCAAwC;GAAI;EAC7E;IACE,iCAAwC;IACxC,gCAAuC;GACxC;EACD;IACE,+BAAuC;IACvC,kCAA0C;GAC3C;EAZD;IAAiC,yBAAmC;GAAI;EACxE;IAAiC,6BAAuC;GAAI;EAC5E;IAAiC,+BAAyC;GAAI;EAC9E;IAAiC,gCAA0C;GAAI;EAC/E;IAAiC,8BAAwC;GAAI;EAC7E;IACE,+BAAwC;IACxC,8BAAuC;GACxC;EACD;IACE,6BAAuC;IACvC,gCAA0C;GAC3C;EAKL;IAAoB,wBAA8B;GAAK;EACvD;IAAoB,4BAA8B;GAAK;EACvD;IAAoB,8BAA8B;GAAK;EACvD;IAAoB,+BAA8B;GAAK;EACvD;IAAoB,6BAA8B;GAAK;EACvD;IACE,8BAA6B;IAC7B,6BAA6B;GAC9B;EACD;IACE,4BAA8B;IAC9B,+BAA8B;GAC/B;ChEovNJ;;AaluNG;EmD/CI;IAAiC,qBAAmC;GAAI;EACxE;IAAiC,yBAAuC;GAAI;EAC5E;IAAiC,2BAAyC;GAAI;EAC9E;IAAiC,4BAA0C;GAAI;EAC/E;IAAiC,0BAAwC;GAAI;EAC7E;IACE,2BAAwC;IACxC,0BAAuC;GACxC;EACD;IACE,yBAAuC;IACvC,4BAA0C;GAC3C;EAZD;IAAiC,2BAAmC;GAAI;EACxE;IAAiC,+BAAuC;GAAI;EAC5E;IAAiC,iCAAyC;GAAI;EAC9E;IAAiC,kCAA0C;GAAI;EAC/E;IAAiC,gCAAwC;GAAI;EAC7E;IACE,iCAAwC;IACxC,gCAAuC;GACxC;EACD;IACE,+BAAuC;IACvC,kCAA0C;GAC3C;EAZD;IAAiC,0BAAmC;GAAI;EACxE;IAAiC,8BAAuC;GAAI;EAC5E;IAAiC,gCAAyC;GAAI;EAC9E;IAAiC,iCAA0C;GAAI;EAC/E;IAAiC,+BAAwC;GAAI;EAC7E;IACE,gCAAwC;IACxC,+BAAuC;GACxC;EACD;IACE,8BAAuC;IACvC,iCAA0C;GAC3C;EAZD;IAAiC,wBAAmC;GAAI;EACxE;IAAiC,4BAAuC;GAAI;EAC5E;IAAiC,8BAAyC;GAAI;EAC9E;IAAiC,+BAA0C;GAAI;EAC/E;IAAiC,6BAAwC;GAAI;EAC7E;IACE,8BAAwC;IACxC,6BAAuC;GACxC;EACD;IACE,4BAAuC;IACvC,+BAA0C;GAC3C;EAZD;IAAiC,0BAAmC;GAAI;EACxE;IAAiC,8BAAuC;GAAI;EAC5E;IAAiC,gCAAyC;GAAI;EAC9E;IAAiC,iCAA0C;GAAI;EAC/E;IAAiC,+BAAwC;GAAI;EAC7E;IACE,gCAAwC;IACxC,+BAAuC;GACxC;EACD;IACE,8BAAuC;IACvC,iCAA0C;GAC3C;EAZD;IAAiC,wBAAmC;GAAI;EACxE;IAAiC,4BAAuC;GAAI;EAC5E;IAAiC,8BAAyC;GAAI;EAC9E;IAAiC,+BAA0C;GAAI;EAC/E;IAAiC,6BAAwC;GAAI;EAC7E;IACE,8BAAwC;IACxC,6BAAuC;GACxC;EACD;IACE,4BAAuC;IACvC,+BAA0C;GAC3C;EAZD;IAAiC,sBAAmC;GAAI;EACxE;IAAiC,0BAAuC;GAAI;EAC5E;IAAiC,4BAAyC;GAAI;EAC9E;IAAiC,6BAA0C;GAAI;EAC/E;IAAiC,2BAAwC;GAAI;EAC7E;IACE,4BAAwC;IACxC,2BAAuC;GACxC;EACD;IACE,0BAAuC;IACvC,6BAA0C;GAC3C;EAZD;IAAiC,4BAAmC;GAAI;EACxE;IAAiC,gCAAuC;GAAI;EAC5E;IAAiC,kCAAyC;GAAI;EAC9E;IAAiC,mCAA0C;GAAI;EAC/E;IAAiC,iCAAwC;GAAI;EAC7E;IACE,kCAAwC;IACxC,iCAAuC;GACxC;EACD;IACE,gCAAuC;IACvC,mCAA0C;GAC3C;EAZD;IAAiC,2BAAmC;GAAI;EACxE;IAAiC,+BAAuC;GAAI;EAC5E;IAAiC,iCAAyC;GAAI;EAC9E;IAAiC,kCAA0C;GAAI;EAC/E;IAAiC,gCAAwC;GAAI;EAC7E;IACE,iCAAwC;IACxC,gCAAuC;GACxC;EACD;IACE,+BAAuC;IACvC,kCAA0C;GAC3C;EAZD;IAAiC,yBAAmC;GAAI;EACxE;IAAiC,6BAAuC;GAAI;EAC5E;IAAiC,+BAAyC;GAAI;EAC9E;IAAiC,gCAA0C;GAAI;EAC/E;IAAiC,8BAAwC;GAAI;EAC7E;IACE,+BAAwC;IACxC,8BAAuC;GACxC;EACD;IACE,6BAAuC;IACvC,gCAA0C;GAC3C;EAZD;IAAiC,2BAAmC;GAAI;EACxE;IAAiC,+BAAuC;GAAI;EAC5E;IAAiC,iCAAyC;GAAI;EAC9E;IAAiC,kCAA0C;GAAI;EAC/E;IAAiC,gCAAwC;GAAI;EAC7E;IACE,iCAAwC;IACxC,gCAAuC;GACxC;EACD;IACE,+BAAuC;IACvC,kCAA0C;GAC3C;EAZD;IAAiC,yBAAmC;GAAI;EACxE;IAAiC,6BAAuC;GAAI;EAC5E;IAAiC,+BAAyC;GAAI;EAC9E;IAAiC,gCAA0C;GAAI;EAC/E;IAAiC,8BAAwC;GAAI;EAC7E;IACE,+BAAwC;IACxC,8BAAuC;GACxC;EACD;IACE,6BAAuC;IACvC,gCAA0C;GAC3C;EAKL;IAAoB,wBAA8B;GAAK;EACvD;IAAoB,4BAA8B;GAAK;EACvD;IAAoB,8BAA8B;GAAK;EACvD;IAAoB,+BAA8B;GAAK;EACvD;IAAoB,6BAA8B;GAAK;EACvD;IACE,8BAA6B;IAC7B,6BAA6B;GAC9B;EACD;IACE,4BAA8B;IAC9B,+BAA8B;GAC/B;ChEkiOJ;;AahhOG;EmD/CI;IAAiC,qBAAmC;GAAI;EACxE;IAAiC,yBAAuC;GAAI;EAC5E;IAAiC,2BAAyC;GAAI;EAC9E;IAAiC,4BAA0C;GAAI;EAC/E;IAAiC,0BAAwC;GAAI;EAC7E;IACE,2BAAwC;IACxC,0BAAuC;GACxC;EACD;IACE,yBAAuC;IACvC,4BAA0C;GAC3C;EAZD;IAAiC,2BAAmC;GAAI;EACxE;IAAiC,+BAAuC;GAAI;EAC5E;IAAiC,iCAAyC;GAAI;EAC9E;IAAiC,kCAA0C;GAAI;EAC/E;IAAiC,gCAAwC;GAAI;EAC7E;IACE,iCAAwC;IACxC,gCAAuC;GACxC;EACD;IACE,+BAAuC;IACvC,kCAA0C;GAC3C;EAZD;IAAiC,0BAAmC;GAAI;EACxE;IAAiC,8BAAuC;GAAI;EAC5E;IAAiC,gCAAyC;GAAI;EAC9E;IAAiC,iCAA0C;GAAI;EAC/E;IAAiC,+BAAwC;GAAI;EAC7E;IACE,gCAAwC;IACxC,+BAAuC;GACxC;EACD;IACE,8BAAuC;IACvC,iCAA0C;GAC3C;EAZD;IAAiC,wBAAmC;GAAI;EACxE;IAAiC,4BAAuC;GAAI;EAC5E;IAAiC,8BAAyC;GAAI;EAC9E;IAAiC,+BAA0C;GAAI;EAC/E;IAAiC,6BAAwC;GAAI;EAC7E;IACE,8BAAwC;IACxC,6BAAuC;GACxC;EACD;IACE,4BAAuC;IACvC,+BAA0C;GAC3C;EAZD;IAAiC,0BAAmC;GAAI;EACxE;IAAiC,8BAAuC;GAAI;EAC5E;IAAiC,gCAAyC;GAAI;EAC9E;IAAiC,iCAA0C;GAAI;EAC/E;IAAiC,+BAAwC;GAAI;EAC7E;IACE,gCAAwC;IACxC,+BAAuC;GACxC;EACD;IACE,8BAAuC;IACvC,iCAA0C;GAC3C;EAZD;IAAiC,wBAAmC;GAAI;EACxE;IAAiC,4BAAuC;GAAI;EAC5E;IAAiC,8BAAyC;GAAI;EAC9E;IAAiC,+BAA0C;GAAI;EAC/E;IAAiC,6BAAwC;GAAI;EAC7E;IACE,8BAAwC;IACxC,6BAAuC;GACxC;EACD;IACE,4BAAuC;IACvC,+BAA0C;GAC3C;EAZD;IAAiC,sBAAmC;GAAI;EACxE;IAAiC,0BAAuC;GAAI;EAC5E;IAAiC,4BAAyC;GAAI;EAC9E;IAAiC,6BAA0C;GAAI;EAC/E;IAAiC,2BAAwC;GAAI;EAC7E;IACE,4BAAwC;IACxC,2BAAuC;GACxC;EACD;IACE,0BAAuC;IACvC,6BAA0C;GAC3C;EAZD;IAAiC,4BAAmC;GAAI;EACxE;IAAiC,gCAAuC;GAAI;EAC5E;IAAiC,kCAAyC;GAAI;EAC9E;IAAiC,mCAA0C;GAAI;EAC/E;IAAiC,iCAAwC;GAAI;EAC7E;IACE,kCAAwC;IACxC,iCAAuC;GACxC;EACD;IACE,gCAAuC;IACvC,mCAA0C;GAC3C;EAZD;IAAiC,2BAAmC;GAAI;EACxE;IAAiC,+BAAuC;GAAI;EAC5E;IAAiC,iCAAyC;GAAI;EAC9E;IAAiC,kCAA0C;GAAI;EAC/E;IAAiC,gCAAwC;GAAI;EAC7E;IACE,iCAAwC;IACxC,gCAAuC;GACxC;EACD;IACE,+BAAuC;IACvC,kCAA0C;GAC3C;EAZD;IAAiC,yBAAmC;GAAI;EACxE;IAAiC,6BAAuC;GAAI;EAC5E;IAAiC,+BAAyC;GAAI;EAC9E;IAAiC,gCAA0C;GAAI;EAC/E;IAAiC,8BAAwC;GAAI;EAC7E;IACE,+BAAwC;IACxC,8BAAuC;GACxC;EACD;IACE,6BAAuC;IACvC,gCAA0C;GAC3C;EAZD;IAAiC,2BAAmC;GAAI;EACxE;IAAiC,+BAAuC;GAAI;EAC5E;IAAiC,iCAAyC;GAAI;EAC9E;IAAiC,kCAA0C;GAAI;EAC/E;IAAiC,gCAAwC;GAAI;EAC7E;IACE,iCAAwC;IACxC,gCAAuC;GACxC;EACD;IACE,+BAAuC;IACvC,kCAA0C;GAC3C;EAZD;IAAiC,yBAAmC;GAAI;EACxE;IAAiC,6BAAuC;GAAI;EAC5E;IAAiC,+BAAyC;GAAI;EAC9E;IAAiC,gCAA0C;GAAI;EAC/E;IAAiC,8BAAwC;GAAI;EAC7E;IACE,+BAAwC;IACxC,8BAAuC;GACxC;EACD;IACE,6BAAuC;IACvC,gCAA0C;GAC3C;EAKL;IAAoB,wBAA8B;GAAK;EACvD;IAAoB,4BAA8B;GAAK;EACvD;IAAoB,8BAA8B;GAAK;EACvD;IAAoB,+BAA8B;GAAK;EACvD;IAAoB,6BAA8B;GAAK;EACvD;IACE,8BAA6B;IAC7B,6BAA6B;GAC9B;EACD;IACE,4BAA8B;IAC9B,+BAA8B;GAC/B;ChEg1OJ;;AiEh3OD;EAAiB,+BAA8B;CAAK;;AACpD;EAAiB,+BAA8B;CAAK;;AACpD;ECJE,iBAAgB;EAChB,wBAAuB;EACvB,oBAAmB;CDEsB;;AAQvC;EAAwB,4BAA2B;CAAK;;AACxD;EAAwB,6BAA4B;CAAK;;AACzD;EAAwB,8BAA6B;CAAK;;ApDsC1D;EoDxCA;IAAwB,4BAA2B;GAAK;EACxD;IAAwB,6BAA4B;GAAK;EACzD;IAAwB,8BAA6B;GAAK;CjE04O7D;;Aap2OG;EoDxCA;IAAwB,4BAA2B;GAAK;EACxD;IAAwB,6BAA4B;GAAK;EACzD;IAAwB,8BAA6B;GAAK;CjEs5O7D;;Aah3OG;EoDxCA;IAAwB,4BAA2B;GAAK;EACxD;IAAwB,6BAA4B;GAAK;EACzD;IAAwB,8BAA6B;GAAK;CjEk6O7D;;Aa53OG;EoDxCA;IAAwB,4BAA2B;GAAK;EACxD;IAAwB,6BAA4B;GAAK;EACzD;IAAwB,8BAA6B;GAAK;CjE86O7D;;AiEx6OD;EAAmB,qCAAoC;CAAK;;AAC5D;EAAmB,qCAAoC;CAAK;;AAC5D;EAAmB,sCAAqC;CAAK;;AAI7D;EAAsB,oB/DmNK;C+DnN+B;;AAC1D;EAAsB,kB/DmNC;C+DnNiC;;AACxD;EAAsB,mBAAkB;CAAK;;AAI7C;EAAc,uBAAsB;CAAK;;AEjCvC;EACE,0BAAwB;CACzB;;AhEiBC;EgEdE,0BAAqC;ChEiBtC;;AgEtBH;EACE,0BAAwB;CACzB;;AhEiBC;EgEdE,0BAAqC;ChEiBtC;;AgEtBH;EACE,0BAAwB;CACzB;;AhEiBC;EgEdE,0BAAqC;ChEiBtC;;AgEtBH;EACE,0BAAwB;CACzB;;AhEiBC;EgEdE,0BAAqC;ChEiBtC;;AgEtBH;EACE,0BAAwB;CACzB;;AhEiBC;EgEdE,0BAAqC;ChEiBtC;;AgEtBH;EACE,0BAAwB;CACzB;;AhEiBC;EgEdE,0BAAqC;ChEiBtC;;AgEtBH;EACE,0BAAwB;CACzB;;AhEiBC;EgEdE,0BAAqC;ChEiBtC;;AgEtBH;EACE,0BAAwB;CACzB;;AhEiBC;EgEdE,0BAAqC;ChEiBtC;;A8DiBL;EAAc,0BAA2B;CAAI;;AAI7C;EG5CE,YAAW;EACX,mBAAkB;EAClB,kBAAiB;EACjB,8BAA6B;EAC7B,UAAS;CH0CV;;AI5CD;ECDE,+BAAkC;CDGnC;;AAED;ECLE,8BAAkC;CDOnC","file":"bootstrap.css","sourcesContent":[null,null,"/*!\n * Bootstrap v4.0.0-alpha.6 (https://getbootstrap.com)\n * Copyright 2011-2017 The Bootstrap Authors\n * Copyright 2011-2017 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n@media print {\n *,\n *::before,\n *::after,\n p::first-letter,\n div::first-letter,\n blockquote::first-letter,\n li::first-letter,\n p::first-line,\n div::first-line,\n blockquote::first-line,\n li::first-line {\n text-shadow: none !important;\n box-shadow: none !important;\n }\n a,\n a:visited {\n text-decoration: underline;\n }\n abbr[title]::after {\n content: \" (\" attr(title) \")\";\n }\n pre {\n white-space: pre-wrap !important;\n }\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n thead {\n display: table-header-group;\n }\n tr,\n img {\n page-break-inside: avoid;\n }\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n h2,\n h3 {\n page-break-after: avoid;\n }\n .navbar {\n display: none;\n }\n .badge {\n border: 1px solid #000;\n }\n .table {\n border-collapse: collapse !important;\n }\n .table td,\n .table th {\n background-color: #fff !important;\n }\n .table-bordered th,\n .table-bordered td {\n border: 1px solid #ddd !important;\n }\n}\n\nhtml {\n box-sizing: border-box;\n font-family: sans-serif;\n line-height: 1.15;\n -webkit-text-size-adjust: 100%;\n -ms-text-size-adjust: 100%;\n -ms-overflow-style: scrollbar;\n -webkit-tap-highlight-color: transparent;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: inherit;\n}\n\n@-ms-viewport {\n width: device-width;\n}\n\narticle, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {\n display: block;\n}\n\nbody {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n font-size: 1rem;\n font-weight: normal;\n line-height: 1.5;\n color: #212529;\n background-color: #fff;\n}\n\n[tabindex=\"-1\"]:focus {\n outline: none !important;\n}\n\nhr {\n box-sizing: content-box;\n height: 0;\n overflow: visible;\n}\n\nh1, h2, h3, h4, h5, h6 {\n margin-top: 0;\n margin-bottom: .5rem;\n}\n\np {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nabbr[title],\nabbr[data-original-title] {\n text-decoration: underline;\n text-decoration: underline dotted;\n cursor: help;\n border-bottom: 0;\n}\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: bold;\n}\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0;\n}\n\nblockquote {\n margin: 0 0 1rem;\n}\n\ndfn {\n font-style: italic;\n}\n\nb,\nstrong {\n font-weight: bolder;\n}\n\nsmall {\n font-size: 80%;\n}\n\nsub,\nsup {\n position: relative;\n font-size: 75%;\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -.25em;\n}\n\nsup {\n top: -.5em;\n}\n\na {\n color: #007bff;\n text-decoration: none;\n background-color: transparent;\n -webkit-text-decoration-skip: objects;\n}\n\na:hover {\n color: #0056b3;\n text-decoration: underline;\n}\n\na:not([href]):not([tabindex]) {\n color: inherit;\n text-decoration: none;\n}\n\na:not([href]):not([tabindex]):focus, a:not([href]):not([tabindex]):hover {\n color: inherit;\n text-decoration: none;\n}\n\na:not([href]):not([tabindex]):focus {\n outline: 0;\n}\n\npre,\ncode,\nkbd,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\n\npre {\n margin-top: 0;\n margin-bottom: 1rem;\n overflow: auto;\n}\n\nfigure {\n margin: 0 0 1rem;\n}\n\nimg {\n vertical-align: middle;\n border-style: none;\n}\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\na,\narea,\nbutton,\n[role=\"button\"],\ninput,\nlabel,\nselect,\nsummary,\ntextarea {\n touch-action: manipulation;\n}\n\ntable {\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: 0.75rem;\n padding-bottom: 0.75rem;\n color: #868e96;\n text-align: left;\n caption-side: bottom;\n}\n\nth {\n text-align: left;\n}\n\nlabel {\n display: inline-block;\n margin-bottom: .5rem;\n}\n\nbutton:focus {\n outline: 1px dotted;\n outline: 5px auto -webkit-focus-ring-color;\n}\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\nbutton,\ninput {\n overflow: visible;\n}\n\nbutton,\nselect {\n text-transform: none;\n}\n\nbutton,\nhtml [type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button;\n}\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n box-sizing: border-box;\n padding: 0;\n}\n\ninput[type=\"date\"],\ninput[type=\"time\"],\ninput[type=\"datetime-local\"],\ninput[type=\"month\"] {\n -webkit-appearance: listbox;\n}\n\ntextarea {\n overflow: auto;\n resize: vertical;\n}\n\nfieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n max-width: 100%;\n padding: 0;\n margin-bottom: .5rem;\n font-size: 1.5rem;\n line-height: inherit;\n color: inherit;\n white-space: normal;\n}\n\nprogress {\n vertical-align: baseline;\n}\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n[type=\"search\"] {\n outline-offset: -2px;\n -webkit-appearance: none;\n}\n\n[type=\"search\"]::-webkit-search-cancel-button,\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n::-webkit-file-upload-button {\n font: inherit;\n -webkit-appearance: button;\n}\n\noutput {\n display: inline-block;\n}\n\nsummary {\n display: list-item;\n}\n\ntemplate {\n display: none;\n}\n\n[hidden] {\n display: none !important;\n}\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n margin-bottom: 0.5rem;\n font-family: inherit;\n font-weight: 500;\n line-height: 1.1;\n color: inherit;\n}\n\nh1, .h1 {\n font-size: 2.5rem;\n}\n\nh2, .h2 {\n font-size: 2rem;\n}\n\nh3, .h3 {\n font-size: 1.75rem;\n}\n\nh4, .h4 {\n font-size: 1.5rem;\n}\n\nh5, .h5 {\n font-size: 1.25rem;\n}\n\nh6, .h6 {\n font-size: 1rem;\n}\n\n.lead {\n font-size: 1.25rem;\n font-weight: 300;\n}\n\n.display-1 {\n font-size: 6rem;\n font-weight: 300;\n line-height: 1.1;\n}\n\n.display-2 {\n font-size: 5.5rem;\n font-weight: 300;\n line-height: 1.1;\n}\n\n.display-3 {\n font-size: 4.5rem;\n font-weight: 300;\n line-height: 1.1;\n}\n\n.display-4 {\n font-size: 3.5rem;\n font-weight: 300;\n line-height: 1.1;\n}\n\nhr {\n margin-top: 1rem;\n margin-bottom: 1rem;\n border: 0;\n border-top: 1px solid rgba(0, 0, 0, 0.1);\n}\n\nsmall,\n.small {\n font-size: 80%;\n font-weight: normal;\n}\n\nmark,\n.mark {\n padding: 0.2em;\n background-color: #fcf8e3;\n}\n\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n\n.list-inline {\n padding-left: 0;\n list-style: none;\n}\n\n.list-inline-item {\n display: inline-block;\n}\n\n.list-inline-item:not(:last-child) {\n margin-right: 5px;\n}\n\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\n\n.blockquote {\n margin-bottom: 1rem;\n font-size: 1.25rem;\n}\n\n.blockquote-footer {\n display: block;\n font-size: 80%;\n color: #868e96;\n}\n\n.blockquote-footer::before {\n content: \"\\2014 \\00A0\";\n}\n\n.img-fluid {\n max-width: 100%;\n height: auto;\n}\n\n.img-thumbnail {\n padding: 0.25rem;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 0.25rem;\n transition: all 0.2s ease-in-out;\n max-width: 100%;\n height: auto;\n}\n\n.figure {\n display: inline-block;\n}\n\n.figure-img {\n margin-bottom: 0.5rem;\n line-height: 1;\n}\n\n.figure-caption {\n font-size: 90%;\n color: #868e96;\n}\n\ncode,\nkbd,\npre,\nsamp {\n font-family: Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n}\n\ncode {\n padding: 0.2rem 0.4rem;\n font-size: 90%;\n color: #bd4147;\n background-color: #f8f9fa;\n border-radius: 0.25rem;\n}\n\na > code {\n padding: 0;\n color: inherit;\n background-color: inherit;\n}\n\nkbd {\n padding: 0.2rem 0.4rem;\n font-size: 90%;\n color: #fff;\n background-color: #212529;\n border-radius: 0.2rem;\n}\n\nkbd kbd {\n padding: 0;\n font-size: 100%;\n font-weight: bold;\n}\n\npre {\n display: block;\n margin-top: 0;\n margin-bottom: 1rem;\n font-size: 90%;\n color: #212529;\n}\n\npre code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n background-color: transparent;\n border-radius: 0;\n}\n\n.pre-scrollable {\n max-height: 340px;\n overflow-y: scroll;\n}\n\n.container {\n margin-right: auto;\n margin-left: auto;\n padding-right: 15px;\n padding-left: 15px;\n}\n\n@media (min-width: 576px) {\n .container {\n width: 540px;\n max-width: 100%;\n }\n}\n\n@media (min-width: 768px) {\n .container {\n width: 720px;\n max-width: 100%;\n }\n}\n\n@media (min-width: 992px) {\n .container {\n width: 960px;\n max-width: 100%;\n }\n}\n\n@media (min-width: 1200px) {\n .container {\n width: 1140px;\n max-width: 100%;\n }\n}\n\n.container-fluid {\n width: 100%;\n margin-right: auto;\n margin-left: auto;\n padding-right: 15px;\n padding-left: 15px;\n}\n\n.row {\n display: flex;\n flex-wrap: wrap;\n margin-right: -15px;\n margin-left: -15px;\n}\n\n.no-gutters {\n margin-right: 0;\n margin-left: 0;\n}\n\n.no-gutters > .col,\n.no-gutters > [class*=\"col-\"] {\n padding-right: 0;\n padding-left: 0;\n}\n\n.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, .col,\n.col-auto, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm,\n.col-sm-auto, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md,\n.col-md-auto, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg,\n.col-lg-auto, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl,\n.col-xl-auto {\n position: relative;\n width: 100%;\n min-height: 1px;\n padding-right: 15px;\n padding-left: 15px;\n}\n\n.col {\n flex-basis: 0;\n flex-grow: 1;\n max-width: 100%;\n}\n\n.col-auto {\n flex: 0 0 auto;\n width: auto;\n max-width: none;\n}\n\n.col-1 {\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n}\n\n.col-2 {\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n}\n\n.col-3 {\n flex: 0 0 25%;\n max-width: 25%;\n}\n\n.col-4 {\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n}\n\n.col-5 {\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n}\n\n.col-6 {\n flex: 0 0 50%;\n max-width: 50%;\n}\n\n.col-7 {\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n}\n\n.col-8 {\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n}\n\n.col-9 {\n flex: 0 0 75%;\n max-width: 75%;\n}\n\n.col-10 {\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n}\n\n.col-11 {\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n}\n\n.col-12 {\n flex: 0 0 100%;\n max-width: 100%;\n}\n\n.order-1 {\n order: 1;\n}\n\n.order-2 {\n order: 2;\n}\n\n.order-3 {\n order: 3;\n}\n\n.order-4 {\n order: 4;\n}\n\n.order-5 {\n order: 5;\n}\n\n.order-6 {\n order: 6;\n}\n\n.order-7 {\n order: 7;\n}\n\n.order-8 {\n order: 8;\n}\n\n.order-9 {\n order: 9;\n}\n\n.order-10 {\n order: 10;\n}\n\n.order-11 {\n order: 11;\n}\n\n.order-12 {\n order: 12;\n}\n\n@media (min-width: 576px) {\n .col-sm {\n flex-basis: 0;\n flex-grow: 1;\n max-width: 100%;\n }\n .col-sm-auto {\n flex: 0 0 auto;\n width: auto;\n max-width: none;\n }\n .col-sm-1 {\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n }\n .col-sm-2 {\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n }\n .col-sm-3 {\n flex: 0 0 25%;\n max-width: 25%;\n }\n .col-sm-4 {\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n }\n .col-sm-5 {\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n }\n .col-sm-6 {\n flex: 0 0 50%;\n max-width: 50%;\n }\n .col-sm-7 {\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n }\n .col-sm-8 {\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n }\n .col-sm-9 {\n flex: 0 0 75%;\n max-width: 75%;\n }\n .col-sm-10 {\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n }\n .col-sm-11 {\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n }\n .col-sm-12 {\n flex: 0 0 100%;\n max-width: 100%;\n }\n .order-sm-1 {\n order: 1;\n }\n .order-sm-2 {\n order: 2;\n }\n .order-sm-3 {\n order: 3;\n }\n .order-sm-4 {\n order: 4;\n }\n .order-sm-5 {\n order: 5;\n }\n .order-sm-6 {\n order: 6;\n }\n .order-sm-7 {\n order: 7;\n }\n .order-sm-8 {\n order: 8;\n }\n .order-sm-9 {\n order: 9;\n }\n .order-sm-10 {\n order: 10;\n }\n .order-sm-11 {\n order: 11;\n }\n .order-sm-12 {\n order: 12;\n }\n}\n\n@media (min-width: 768px) {\n .col-md {\n flex-basis: 0;\n flex-grow: 1;\n max-width: 100%;\n }\n .col-md-auto {\n flex: 0 0 auto;\n width: auto;\n max-width: none;\n }\n .col-md-1 {\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n }\n .col-md-2 {\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n }\n .col-md-3 {\n flex: 0 0 25%;\n max-width: 25%;\n }\n .col-md-4 {\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n }\n .col-md-5 {\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n }\n .col-md-6 {\n flex: 0 0 50%;\n max-width: 50%;\n }\n .col-md-7 {\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n }\n .col-md-8 {\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n }\n .col-md-9 {\n flex: 0 0 75%;\n max-width: 75%;\n }\n .col-md-10 {\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n }\n .col-md-11 {\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n }\n .col-md-12 {\n flex: 0 0 100%;\n max-width: 100%;\n }\n .order-md-1 {\n order: 1;\n }\n .order-md-2 {\n order: 2;\n }\n .order-md-3 {\n order: 3;\n }\n .order-md-4 {\n order: 4;\n }\n .order-md-5 {\n order: 5;\n }\n .order-md-6 {\n order: 6;\n }\n .order-md-7 {\n order: 7;\n }\n .order-md-8 {\n order: 8;\n }\n .order-md-9 {\n order: 9;\n }\n .order-md-10 {\n order: 10;\n }\n .order-md-11 {\n order: 11;\n }\n .order-md-12 {\n order: 12;\n }\n}\n\n@media (min-width: 992px) {\n .col-lg {\n flex-basis: 0;\n flex-grow: 1;\n max-width: 100%;\n }\n .col-lg-auto {\n flex: 0 0 auto;\n width: auto;\n max-width: none;\n }\n .col-lg-1 {\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n }\n .col-lg-2 {\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n }\n .col-lg-3 {\n flex: 0 0 25%;\n max-width: 25%;\n }\n .col-lg-4 {\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n }\n .col-lg-5 {\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n }\n .col-lg-6 {\n flex: 0 0 50%;\n max-width: 50%;\n }\n .col-lg-7 {\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n }\n .col-lg-8 {\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n }\n .col-lg-9 {\n flex: 0 0 75%;\n max-width: 75%;\n }\n .col-lg-10 {\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n }\n .col-lg-11 {\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n }\n .col-lg-12 {\n flex: 0 0 100%;\n max-width: 100%;\n }\n .order-lg-1 {\n order: 1;\n }\n .order-lg-2 {\n order: 2;\n }\n .order-lg-3 {\n order: 3;\n }\n .order-lg-4 {\n order: 4;\n }\n .order-lg-5 {\n order: 5;\n }\n .order-lg-6 {\n order: 6;\n }\n .order-lg-7 {\n order: 7;\n }\n .order-lg-8 {\n order: 8;\n }\n .order-lg-9 {\n order: 9;\n }\n .order-lg-10 {\n order: 10;\n }\n .order-lg-11 {\n order: 11;\n }\n .order-lg-12 {\n order: 12;\n }\n}\n\n@media (min-width: 1200px) {\n .col-xl {\n flex-basis: 0;\n flex-grow: 1;\n max-width: 100%;\n }\n .col-xl-auto {\n flex: 0 0 auto;\n width: auto;\n max-width: none;\n }\n .col-xl-1 {\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n }\n .col-xl-2 {\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n }\n .col-xl-3 {\n flex: 0 0 25%;\n max-width: 25%;\n }\n .col-xl-4 {\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n }\n .col-xl-5 {\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n }\n .col-xl-6 {\n flex: 0 0 50%;\n max-width: 50%;\n }\n .col-xl-7 {\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n }\n .col-xl-8 {\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n }\n .col-xl-9 {\n flex: 0 0 75%;\n max-width: 75%;\n }\n .col-xl-10 {\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n }\n .col-xl-11 {\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n }\n .col-xl-12 {\n flex: 0 0 100%;\n max-width: 100%;\n }\n .order-xl-1 {\n order: 1;\n }\n .order-xl-2 {\n order: 2;\n }\n .order-xl-3 {\n order: 3;\n }\n .order-xl-4 {\n order: 4;\n }\n .order-xl-5 {\n order: 5;\n }\n .order-xl-6 {\n order: 6;\n }\n .order-xl-7 {\n order: 7;\n }\n .order-xl-8 {\n order: 8;\n }\n .order-xl-9 {\n order: 9;\n }\n .order-xl-10 {\n order: 10;\n }\n .order-xl-11 {\n order: 11;\n }\n .order-xl-12 {\n order: 12;\n }\n}\n\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: 1rem;\n background-color: transparent;\n}\n\n.table th,\n.table td {\n padding: 0.75rem;\n vertical-align: top;\n border-top: 1px solid #e9ecef;\n}\n\n.table thead th {\n vertical-align: bottom;\n border-bottom: 2px solid #e9ecef;\n}\n\n.table tbody + tbody {\n border-top: 2px solid #e9ecef;\n}\n\n.table .table {\n background-color: #fff;\n}\n\n.table-sm th,\n.table-sm td {\n padding: 0.3rem;\n}\n\n.table-bordered {\n border: 1px solid #e9ecef;\n}\n\n.table-bordered th,\n.table-bordered td {\n border: 1px solid #e9ecef;\n}\n\n.table-bordered thead th,\n.table-bordered thead td {\n border-bottom-width: 2px;\n}\n\n.table-striped tbody tr:nth-of-type(odd) {\n background-color: rgba(0, 0, 0, 0.05);\n}\n\n.table-hover tbody tr:hover {\n background-color: rgba(0, 0, 0, 0.075);\n}\n\n.table-primary,\n.table-primary > th,\n.table-primary > td {\n background-color: #b8daff;\n}\n\n.table-hover .table-primary:hover {\n background-color: #9fcdff;\n}\n\n.table-hover .table-primary:hover > td,\n.table-hover .table-primary:hover > th {\n background-color: #9fcdff;\n}\n\n.table-secondary,\n.table-secondary > th,\n.table-secondary > td {\n background-color: #dddfe2;\n}\n\n.table-hover .table-secondary:hover {\n background-color: #cfd2d6;\n}\n\n.table-hover .table-secondary:hover > td,\n.table-hover .table-secondary:hover > th {\n background-color: #cfd2d6;\n}\n\n.table-success,\n.table-success > th,\n.table-success > td {\n background-color: #c3e6cb;\n}\n\n.table-hover .table-success:hover {\n background-color: #b1dfbb;\n}\n\n.table-hover .table-success:hover > td,\n.table-hover .table-success:hover > th {\n background-color: #b1dfbb;\n}\n\n.table-info,\n.table-info > th,\n.table-info > td {\n background-color: #bee5eb;\n}\n\n.table-hover .table-info:hover {\n background-color: #abdde5;\n}\n\n.table-hover .table-info:hover > td,\n.table-hover .table-info:hover > th {\n background-color: #abdde5;\n}\n\n.table-warning,\n.table-warning > th,\n.table-warning > td {\n background-color: #ffeeba;\n}\n\n.table-hover .table-warning:hover {\n background-color: #ffe8a1;\n}\n\n.table-hover .table-warning:hover > td,\n.table-hover .table-warning:hover > th {\n background-color: #ffe8a1;\n}\n\n.table-danger,\n.table-danger > th,\n.table-danger > td {\n background-color: #f5c6cb;\n}\n\n.table-hover .table-danger:hover {\n background-color: #f1b0b7;\n}\n\n.table-hover .table-danger:hover > td,\n.table-hover .table-danger:hover > th {\n background-color: #f1b0b7;\n}\n\n.table-light,\n.table-light > th,\n.table-light > td {\n background-color: #fdfdfe;\n}\n\n.table-hover .table-light:hover {\n background-color: #ececf6;\n}\n\n.table-hover .table-light:hover > td,\n.table-hover .table-light:hover > th {\n background-color: #ececf6;\n}\n\n.table-dark,\n.table-dark > th,\n.table-dark > td {\n background-color: #c6c8ca;\n}\n\n.table-hover .table-dark:hover {\n background-color: #b9bbbe;\n}\n\n.table-hover .table-dark:hover > td,\n.table-hover .table-dark:hover > th {\n background-color: #b9bbbe;\n}\n\n.table-active,\n.table-active > th,\n.table-active > td {\n background-color: rgba(0, 0, 0, 0.075);\n}\n\n.table-hover .table-active:hover {\n background-color: rgba(0, 0, 0, 0.075);\n}\n\n.table-hover .table-active:hover > td,\n.table-hover .table-active:hover > th {\n background-color: rgba(0, 0, 0, 0.075);\n}\n\n.thead-inverse th {\n color: #fff;\n background-color: #212529;\n}\n\n.thead-default th {\n color: #495057;\n background-color: #e9ecef;\n}\n\n.table-inverse {\n color: #fff;\n background-color: #212529;\n}\n\n.table-inverse th,\n.table-inverse td,\n.table-inverse thead th {\n border-color: #32383e;\n}\n\n.table-inverse.table-bordered {\n border: 0;\n}\n\n.table-inverse.table-striped tbody tr:nth-of-type(odd) {\n background-color: rgba(255, 255, 255, 0.05);\n}\n\n.table-inverse.table-hover tbody tr:hover {\n background-color: rgba(255, 255, 255, 0.075);\n}\n\n@media (max-width: 991px) {\n .table-responsive {\n display: block;\n width: 100%;\n overflow-x: auto;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n }\n .table-responsive.table-bordered {\n border: 0;\n }\n}\n\n.form-control {\n display: block;\n width: 100%;\n padding: 0.5rem 0.75rem;\n font-size: 1rem;\n line-height: 1.25;\n color: #495057;\n background-color: #fff;\n background-image: none;\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 0.25rem;\n transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;\n}\n\n.form-control::-ms-expand {\n background-color: transparent;\n border: 0;\n}\n\n.form-control:focus {\n color: #495057;\n background-color: #fff;\n border-color: #80bdff;\n outline: none;\n}\n\n.form-control::placeholder {\n color: #868e96;\n opacity: 1;\n}\n\n.form-control:disabled, .form-control[readonly] {\n background-color: #e9ecef;\n opacity: 1;\n}\n\nselect.form-control:not([size]):not([multiple]) {\n height: calc(2.25rem + 2px);\n}\n\nselect.form-control:focus::-ms-value {\n color: #495057;\n background-color: #fff;\n}\n\n.form-control-file,\n.form-control-range {\n display: block;\n}\n\n.col-form-label {\n padding-top: calc(0.5rem - 1px * 2);\n padding-bottom: calc(0.5rem - 1px * 2);\n margin-bottom: 0;\n}\n\n.col-form-label-lg {\n padding-top: calc(0.5rem - 1px * 2);\n padding-bottom: calc(0.5rem - 1px * 2);\n font-size: 1.25rem;\n}\n\n.col-form-label-sm {\n padding-top: calc(0.25rem - 1px * 2);\n padding-bottom: calc(0.25rem - 1px * 2);\n font-size: 0.875rem;\n}\n\n.col-form-legend {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n margin-bottom: 0;\n font-size: 1rem;\n}\n\n.form-control-plaintext {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n margin-bottom: 0;\n line-height: 1.25;\n border: solid transparent;\n border-width: 1px 0;\n}\n\n.form-control-plaintext.form-control-sm, .input-group-sm > .form-control-plaintext.form-control,\n.input-group-sm > .form-control-plaintext.input-group-addon,\n.input-group-sm > .input-group-btn > .form-control-plaintext.btn, .form-control-plaintext.form-control-lg, .input-group-lg > .form-control-plaintext.form-control,\n.input-group-lg > .form-control-plaintext.input-group-addon,\n.input-group-lg > .input-group-btn > .form-control-plaintext.btn {\n padding-right: 0;\n padding-left: 0;\n}\n\n.form-control-sm, .input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n line-height: 1.5;\n border-radius: 0.2rem;\n}\n\nselect.form-control-sm:not([size]):not([multiple]), .input-group-sm > select.form-control:not([size]):not([multiple]),\n.input-group-sm > select.input-group-addon:not([size]):not([multiple]),\n.input-group-sm > .input-group-btn > select.btn:not([size]):not([multiple]) {\n height: calc(1.8125rem + 2px);\n}\n\n.form-control-lg, .input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n line-height: 1.5;\n border-radius: 0.3rem;\n}\n\nselect.form-control-lg:not([size]):not([multiple]), .input-group-lg > select.form-control:not([size]):not([multiple]),\n.input-group-lg > select.input-group-addon:not([size]):not([multiple]),\n.input-group-lg > .input-group-btn > select.btn:not([size]):not([multiple]) {\n height: calc(2.3125rem + 2px);\n}\n\n.form-group {\n margin-bottom: 1rem;\n}\n\n.form-text {\n display: block;\n margin-top: 0.25rem;\n}\n\n.form-row {\n display: flex;\n flex-wrap: wrap;\n margin-right: -5px;\n margin-left: -5px;\n}\n\n.form-row > .col,\n.form-row > [class*=\"col-\"] {\n padding-right: 5px;\n padding-left: 5px;\n}\n\n.form-check {\n position: relative;\n display: block;\n margin-bottom: 0.5rem;\n}\n\n.form-check.disabled .form-check-label {\n color: #868e96;\n}\n\n.form-check-label {\n padding-left: 1.25rem;\n margin-bottom: 0;\n}\n\n.form-check-input {\n position: absolute;\n margin-top: 0.25rem;\n margin-left: -1.25rem;\n}\n\n.form-check-input:only-child {\n position: static;\n}\n\n.form-check-inline {\n display: inline-block;\n}\n\n.form-check-inline .form-check-label {\n vertical-align: middle;\n}\n\n.form-check-inline + .form-check-inline {\n margin-left: 0.75rem;\n}\n\n.invalid-feedback {\n display: none;\n margin-top: .25rem;\n font-size: .875rem;\n color: #dc3545;\n}\n\n.invalid-tooltip {\n position: absolute;\n top: 100%;\n z-index: 5;\n display: none;\n width: 250px;\n padding: .5rem;\n margin-top: .1rem;\n font-size: .875rem;\n line-height: 1;\n color: #fff;\n background-color: rgba(220, 53, 69, 0.8);\n border-radius: .2rem;\n}\n\n.was-validated .form-control:valid, .form-control.is-valid, .was-validated\n.custom-select:valid,\n.custom-select.is-valid {\n border-color: #28a745;\n}\n\n.was-validated .form-control:valid:focus, .form-control.is-valid:focus, .was-validated\n.custom-select:valid:focus,\n.custom-select.is-valid:focus {\n box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);\n}\n\n.was-validated .form-control:valid ~ .invalid-feedback,\n.was-validated .form-control:valid ~ .invalid-tooltip, .form-control.is-valid ~ .invalid-feedback,\n.form-control.is-valid ~ .invalid-tooltip, .was-validated\n.custom-select:valid ~ .invalid-feedback,\n.was-validated\n.custom-select:valid ~ .invalid-tooltip,\n.custom-select.is-valid ~ .invalid-feedback,\n.custom-select.is-valid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated .form-check-input:valid + .form-check-label, .form-check-input.is-valid + .form-check-label {\n color: #28a745;\n}\n\n.was-validated .custom-control-input:valid ~ .custom-control-indicator, .custom-control-input.is-valid ~ .custom-control-indicator {\n background-color: rgba(40, 167, 69, 0.25);\n}\n\n.was-validated .custom-control-input:valid ~ .custom-control-description, .custom-control-input.is-valid ~ .custom-control-description {\n color: #28a745;\n}\n\n.was-validated .custom-file-input:valid ~ .custom-file-control, .custom-file-input.is-valid ~ .custom-file-control {\n border-color: #28a745;\n}\n\n.was-validated .custom-file-input:valid ~ .custom-file-control::before, .custom-file-input.is-valid ~ .custom-file-control::before {\n border-color: inherit;\n}\n\n.was-validated .custom-file-input:valid:focus, .custom-file-input.is-valid:focus {\n box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);\n}\n\n.was-validated .form-control:invalid, .form-control.is-invalid, .was-validated\n.custom-select:invalid,\n.custom-select.is-invalid {\n border-color: #dc3545;\n}\n\n.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus, .was-validated\n.custom-select:invalid:focus,\n.custom-select.is-invalid:focus {\n box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);\n}\n\n.was-validated .form-control:invalid ~ .invalid-feedback,\n.was-validated .form-control:invalid ~ .invalid-tooltip, .form-control.is-invalid ~ .invalid-feedback,\n.form-control.is-invalid ~ .invalid-tooltip, .was-validated\n.custom-select:invalid ~ .invalid-feedback,\n.was-validated\n.custom-select:invalid ~ .invalid-tooltip,\n.custom-select.is-invalid ~ .invalid-feedback,\n.custom-select.is-invalid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated .form-check-input:invalid + .form-check-label, .form-check-input.is-invalid + .form-check-label {\n color: #dc3545;\n}\n\n.was-validated .custom-control-input:invalid ~ .custom-control-indicator, .custom-control-input.is-invalid ~ .custom-control-indicator {\n background-color: rgba(220, 53, 69, 0.25);\n}\n\n.was-validated .custom-control-input:invalid ~ .custom-control-description, .custom-control-input.is-invalid ~ .custom-control-description {\n color: #dc3545;\n}\n\n.was-validated .custom-file-input:invalid ~ .custom-file-control, .custom-file-input.is-invalid ~ .custom-file-control {\n border-color: #dc3545;\n}\n\n.was-validated .custom-file-input:invalid ~ .custom-file-control::before, .custom-file-input.is-invalid ~ .custom-file-control::before {\n border-color: inherit;\n}\n\n.was-validated .custom-file-input:invalid:focus, .custom-file-input.is-invalid:focus {\n box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);\n}\n\n.form-inline {\n display: flex;\n flex-flow: row wrap;\n align-items: center;\n}\n\n.form-inline .form-check {\n width: 100%;\n}\n\n@media (min-width: 576px) {\n .form-inline label {\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 0;\n }\n .form-inline .form-group {\n display: flex;\n flex: 0 0 auto;\n flex-flow: row wrap;\n align-items: center;\n margin-bottom: 0;\n }\n .form-inline .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .form-inline .form-control-plaintext {\n display: inline-block;\n }\n .form-inline .input-group {\n width: auto;\n }\n .form-inline .form-control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .form-check {\n display: flex;\n align-items: center;\n justify-content: center;\n width: auto;\n margin-top: 0;\n margin-bottom: 0;\n }\n .form-inline .form-check-label {\n padding-left: 0;\n }\n .form-inline .form-check-input {\n position: relative;\n margin-top: 0;\n margin-right: 0.25rem;\n margin-left: 0;\n }\n .form-inline .custom-control {\n display: flex;\n align-items: center;\n justify-content: center;\n padding-left: 0;\n }\n .form-inline .custom-control-indicator {\n position: static;\n display: inline-block;\n margin-right: 0.25rem;\n vertical-align: text-bottom;\n }\n .form-inline .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n\n.btn {\n display: inline-block;\n font-weight: normal;\n text-align: center;\n white-space: nowrap;\n vertical-align: middle;\n user-select: none;\n border: 1px solid transparent;\n padding: 0.5rem 0.75rem;\n font-size: 1rem;\n line-height: 1.25;\n border-radius: 0.25rem;\n transition: all 0.15s ease-in-out;\n}\n\n.btn:focus, .btn:hover {\n text-decoration: none;\n}\n\n.btn:focus, .btn.focus {\n outline: 0;\n box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);\n}\n\n.btn.disabled, .btn:disabled {\n opacity: .65;\n}\n\n.btn:active, .btn.active {\n background-image: none;\n}\n\na.btn.disabled,\nfieldset[disabled] a.btn {\n pointer-events: none;\n}\n\n.btn-primary {\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.btn-primary:hover {\n color: #fff;\n background-color: #0069d9;\n border-color: #0062cc;\n}\n\n.btn-primary:focus, .btn-primary.focus {\n box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.5);\n}\n\n.btn-primary.disabled, .btn-primary:disabled {\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.btn-primary:active, .btn-primary.active,\n.show > .btn-primary.dropdown-toggle {\n background-color: #0069d9;\n background-image: none;\n border-color: #0062cc;\n}\n\n.btn-secondary {\n color: #fff;\n background-color: #868e96;\n border-color: #868e96;\n}\n\n.btn-secondary:hover {\n color: #fff;\n background-color: #727b84;\n border-color: #6c757d;\n}\n\n.btn-secondary:focus, .btn-secondary.focus {\n box-shadow: 0 0 0 3px rgba(134, 142, 150, 0.5);\n}\n\n.btn-secondary.disabled, .btn-secondary:disabled {\n background-color: #868e96;\n border-color: #868e96;\n}\n\n.btn-secondary:active, .btn-secondary.active,\n.show > .btn-secondary.dropdown-toggle {\n background-color: #727b84;\n background-image: none;\n border-color: #6c757d;\n}\n\n.btn-success {\n color: #fff;\n background-color: #28a745;\n border-color: #28a745;\n}\n\n.btn-success:hover {\n color: #fff;\n background-color: #218838;\n border-color: #1e7e34;\n}\n\n.btn-success:focus, .btn-success.focus {\n box-shadow: 0 0 0 3px rgba(40, 167, 69, 0.5);\n}\n\n.btn-success.disabled, .btn-success:disabled {\n background-color: #28a745;\n border-color: #28a745;\n}\n\n.btn-success:active, .btn-success.active,\n.show > .btn-success.dropdown-toggle {\n background-color: #218838;\n background-image: none;\n border-color: #1e7e34;\n}\n\n.btn-info {\n color: #fff;\n background-color: #17a2b8;\n border-color: #17a2b8;\n}\n\n.btn-info:hover {\n color: #fff;\n background-color: #138496;\n border-color: #117a8b;\n}\n\n.btn-info:focus, .btn-info.focus {\n box-shadow: 0 0 0 3px rgba(23, 162, 184, 0.5);\n}\n\n.btn-info.disabled, .btn-info:disabled {\n background-color: #17a2b8;\n border-color: #17a2b8;\n}\n\n.btn-info:active, .btn-info.active,\n.show > .btn-info.dropdown-toggle {\n background-color: #138496;\n background-image: none;\n border-color: #117a8b;\n}\n\n.btn-warning {\n color: #111;\n background-color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-warning:hover {\n color: #111;\n background-color: #e0a800;\n border-color: #d39e00;\n}\n\n.btn-warning:focus, .btn-warning.focus {\n box-shadow: 0 0 0 3px rgba(255, 193, 7, 0.5);\n}\n\n.btn-warning.disabled, .btn-warning:disabled {\n background-color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-warning:active, .btn-warning.active,\n.show > .btn-warning.dropdown-toggle {\n background-color: #e0a800;\n background-image: none;\n border-color: #d39e00;\n}\n\n.btn-danger {\n color: #fff;\n background-color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-danger:hover {\n color: #fff;\n background-color: #c82333;\n border-color: #bd2130;\n}\n\n.btn-danger:focus, .btn-danger.focus {\n box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.5);\n}\n\n.btn-danger.disabled, .btn-danger:disabled {\n background-color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-danger:active, .btn-danger.active,\n.show > .btn-danger.dropdown-toggle {\n background-color: #c82333;\n background-image: none;\n border-color: #bd2130;\n}\n\n.btn-light {\n color: #111;\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-light:hover {\n color: #111;\n background-color: #e2e6ea;\n border-color: #dae0e5;\n}\n\n.btn-light:focus, .btn-light.focus {\n box-shadow: 0 0 0 3px rgba(248, 249, 250, 0.5);\n}\n\n.btn-light.disabled, .btn-light:disabled {\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-light:active, .btn-light.active,\n.show > .btn-light.dropdown-toggle {\n background-color: #e2e6ea;\n background-image: none;\n border-color: #dae0e5;\n}\n\n.btn-dark {\n color: #fff;\n background-color: #343a40;\n border-color: #343a40;\n}\n\n.btn-dark:hover {\n color: #fff;\n background-color: #23272b;\n border-color: #1d2124;\n}\n\n.btn-dark:focus, .btn-dark.focus {\n box-shadow: 0 0 0 3px rgba(52, 58, 64, 0.5);\n}\n\n.btn-dark.disabled, .btn-dark:disabled {\n background-color: #343a40;\n border-color: #343a40;\n}\n\n.btn-dark:active, .btn-dark.active,\n.show > .btn-dark.dropdown-toggle {\n background-color: #23272b;\n background-image: none;\n border-color: #1d2124;\n}\n\n.btn-outline-primary {\n color: #007bff;\n background-color: transparent;\n background-image: none;\n border-color: #007bff;\n}\n\n.btn-outline-primary:hover {\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.btn-outline-primary:focus, .btn-outline-primary.focus {\n box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.5);\n}\n\n.btn-outline-primary.disabled, .btn-outline-primary:disabled {\n color: #007bff;\n background-color: transparent;\n}\n\n.btn-outline-primary:active, .btn-outline-primary.active,\n.show > .btn-outline-primary.dropdown-toggle {\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.btn-outline-secondary {\n color: #868e96;\n background-color: transparent;\n background-image: none;\n border-color: #868e96;\n}\n\n.btn-outline-secondary:hover {\n color: #fff;\n background-color: #868e96;\n border-color: #868e96;\n}\n\n.btn-outline-secondary:focus, .btn-outline-secondary.focus {\n box-shadow: 0 0 0 3px rgba(134, 142, 150, 0.5);\n}\n\n.btn-outline-secondary.disabled, .btn-outline-secondary:disabled {\n color: #868e96;\n background-color: transparent;\n}\n\n.btn-outline-secondary:active, .btn-outline-secondary.active,\n.show > .btn-outline-secondary.dropdown-toggle {\n color: #fff;\n background-color: #868e96;\n border-color: #868e96;\n}\n\n.btn-outline-success {\n color: #28a745;\n background-color: transparent;\n background-image: none;\n border-color: #28a745;\n}\n\n.btn-outline-success:hover {\n color: #fff;\n background-color: #28a745;\n border-color: #28a745;\n}\n\n.btn-outline-success:focus, .btn-outline-success.focus {\n box-shadow: 0 0 0 3px rgba(40, 167, 69, 0.5);\n}\n\n.btn-outline-success.disabled, .btn-outline-success:disabled {\n color: #28a745;\n background-color: transparent;\n}\n\n.btn-outline-success:active, .btn-outline-success.active,\n.show > .btn-outline-success.dropdown-toggle {\n color: #fff;\n background-color: #28a745;\n border-color: #28a745;\n}\n\n.btn-outline-info {\n color: #17a2b8;\n background-color: transparent;\n background-image: none;\n border-color: #17a2b8;\n}\n\n.btn-outline-info:hover {\n color: #fff;\n background-color: #17a2b8;\n border-color: #17a2b8;\n}\n\n.btn-outline-info:focus, .btn-outline-info.focus {\n box-shadow: 0 0 0 3px rgba(23, 162, 184, 0.5);\n}\n\n.btn-outline-info.disabled, .btn-outline-info:disabled {\n color: #17a2b8;\n background-color: transparent;\n}\n\n.btn-outline-info:active, .btn-outline-info.active,\n.show > .btn-outline-info.dropdown-toggle {\n color: #fff;\n background-color: #17a2b8;\n border-color: #17a2b8;\n}\n\n.btn-outline-warning {\n color: #ffc107;\n background-color: transparent;\n background-image: none;\n border-color: #ffc107;\n}\n\n.btn-outline-warning:hover {\n color: #fff;\n background-color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-outline-warning:focus, .btn-outline-warning.focus {\n box-shadow: 0 0 0 3px rgba(255, 193, 7, 0.5);\n}\n\n.btn-outline-warning.disabled, .btn-outline-warning:disabled {\n color: #ffc107;\n background-color: transparent;\n}\n\n.btn-outline-warning:active, .btn-outline-warning.active,\n.show > .btn-outline-warning.dropdown-toggle {\n color: #fff;\n background-color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-outline-danger {\n color: #dc3545;\n background-color: transparent;\n background-image: none;\n border-color: #dc3545;\n}\n\n.btn-outline-danger:hover {\n color: #fff;\n background-color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-outline-danger:focus, .btn-outline-danger.focus {\n box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.5);\n}\n\n.btn-outline-danger.disabled, .btn-outline-danger:disabled {\n color: #dc3545;\n background-color: transparent;\n}\n\n.btn-outline-danger:active, .btn-outline-danger.active,\n.show > .btn-outline-danger.dropdown-toggle {\n color: #fff;\n background-color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-outline-light {\n color: #f8f9fa;\n background-color: transparent;\n background-image: none;\n border-color: #f8f9fa;\n}\n\n.btn-outline-light:hover {\n color: #fff;\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-outline-light:focus, .btn-outline-light.focus {\n box-shadow: 0 0 0 3px rgba(248, 249, 250, 0.5);\n}\n\n.btn-outline-light.disabled, .btn-outline-light:disabled {\n color: #f8f9fa;\n background-color: transparent;\n}\n\n.btn-outline-light:active, .btn-outline-light.active,\n.show > .btn-outline-light.dropdown-toggle {\n color: #fff;\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-outline-dark {\n color: #343a40;\n background-color: transparent;\n background-image: none;\n border-color: #343a40;\n}\n\n.btn-outline-dark:hover {\n color: #fff;\n background-color: #343a40;\n border-color: #343a40;\n}\n\n.btn-outline-dark:focus, .btn-outline-dark.focus {\n box-shadow: 0 0 0 3px rgba(52, 58, 64, 0.5);\n}\n\n.btn-outline-dark.disabled, .btn-outline-dark:disabled {\n color: #343a40;\n background-color: transparent;\n}\n\n.btn-outline-dark:active, .btn-outline-dark.active,\n.show > .btn-outline-dark.dropdown-toggle {\n color: #fff;\n background-color: #343a40;\n border-color: #343a40;\n}\n\n.btn-link {\n font-weight: normal;\n color: #007bff;\n border-radius: 0;\n}\n\n.btn-link, .btn-link:active, .btn-link.active, .btn-link:disabled {\n background-color: transparent;\n}\n\n.btn-link, .btn-link:focus, .btn-link:active {\n border-color: transparent;\n}\n\n.btn-link:hover {\n border-color: transparent;\n}\n\n.btn-link:focus, .btn-link:hover {\n color: #0056b3;\n text-decoration: underline;\n background-color: transparent;\n}\n\n.btn-link:disabled {\n color: #868e96;\n}\n\n.btn-link:disabled:focus, .btn-link:disabled:hover {\n text-decoration: none;\n}\n\n.btn-lg, .btn-group-lg > .btn {\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n line-height: 1.5;\n border-radius: 0.3rem;\n}\n\n.btn-sm, .btn-group-sm > .btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n line-height: 1.5;\n border-radius: 0.2rem;\n}\n\n.btn-block {\n display: block;\n width: 100%;\n}\n\n.btn-block + .btn-block {\n margin-top: 0.5rem;\n}\n\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n width: 100%;\n}\n\n.fade {\n opacity: 0;\n transition: opacity 0.15s linear;\n}\n\n.fade.show {\n opacity: 1;\n}\n\n.collapse {\n display: none;\n}\n\n.collapse.show {\n display: block;\n}\n\ntr.collapse.show {\n display: table-row;\n}\n\ntbody.collapse.show {\n display: table-row-group;\n}\n\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n transition: height 0.35s ease;\n}\n\n.dropup,\n.dropdown {\n position: relative;\n}\n\n.dropdown-toggle::after {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0.3em solid;\n border-right: 0.3em solid transparent;\n border-left: 0.3em solid transparent;\n}\n\n.dropdown-toggle:empty::after {\n margin-left: 0;\n}\n\n.dropup .dropdown-toggle::after {\n border-top: 0;\n border-bottom: 0.3em solid;\n}\n\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 1000;\n display: none;\n float: left;\n min-width: 10rem;\n padding: 0.5rem 0;\n margin: 0.125rem 0 0;\n font-size: 1rem;\n color: #212529;\n text-align: left;\n list-style: none;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 0.25rem;\n}\n\n.dropdown-divider {\n height: 0;\n margin: 0.5rem 0;\n overflow: hidden;\n border-top: 1px solid #e9ecef;\n}\n\n.dropdown-item {\n display: block;\n width: 100%;\n padding: 0.25rem 1.5rem;\n clear: both;\n font-weight: normal;\n color: #212529;\n text-align: inherit;\n white-space: nowrap;\n background: none;\n border: 0;\n}\n\n.dropdown-item:focus, .dropdown-item:hover {\n color: #16181b;\n text-decoration: none;\n background-color: #f8f9fa;\n}\n\n.dropdown-item.active, .dropdown-item:active {\n color: #fff;\n text-decoration: none;\n background-color: #007bff;\n}\n\n.dropdown-item.disabled, .dropdown-item:disabled {\n color: #868e96;\n background-color: transparent;\n}\n\n.show > a {\n outline: 0;\n}\n\n.dropdown-menu.show {\n display: block;\n}\n\n.dropdown-header {\n display: block;\n padding: 0.5rem 1.5rem;\n margin-bottom: 0;\n font-size: 0.875rem;\n color: #868e96;\n white-space: nowrap;\n}\n\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-flex;\n vertical-align: middle;\n}\n\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n flex: 0 1 auto;\n margin-bottom: 0;\n}\n\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover {\n z-index: 2;\n}\n\n.btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active,\n.btn-group-vertical > .btn:focus,\n.btn-group-vertical > .btn:active,\n.btn-group-vertical > .btn.active {\n z-index: 2;\n}\n\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group,\n.btn-group-vertical .btn + .btn,\n.btn-group-vertical .btn + .btn-group,\n.btn-group-vertical .btn-group + .btn,\n.btn-group-vertical .btn-group + .btn-group {\n margin-left: -1px;\n}\n\n.btn-toolbar {\n display: flex;\n flex-wrap: wrap;\n justify-content: flex-start;\n}\n\n.btn-toolbar .input-group {\n width: auto;\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n\n.btn-group > .btn:first-child {\n margin-left: 0;\n}\n\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.btn-group > .btn-group {\n float: left;\n}\n\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.btn + .dropdown-toggle-split {\n padding-right: 0.5625rem;\n padding-left: 0.5625rem;\n}\n\n.btn + .dropdown-toggle-split::after {\n margin-left: 0;\n}\n\n.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split {\n padding-right: 0.375rem;\n padding-left: 0.375rem;\n}\n\n.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split {\n padding-right: 0.75rem;\n padding-left: 0.75rem;\n}\n\n.btn-group-vertical {\n display: inline-flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: center;\n}\n\n.btn-group-vertical .btn,\n.btn-group-vertical .btn-group {\n width: 100%;\n}\n\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n}\n\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n\n.input-group {\n position: relative;\n display: flex;\n width: 100%;\n}\n\n.input-group .form-control {\n position: relative;\n z-index: 2;\n flex: 1 1 auto;\n width: 1%;\n margin-bottom: 0;\n}\n\n.input-group .form-control:focus, .input-group .form-control:active, .input-group .form-control:hover {\n z-index: 3;\n}\n\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: flex;\n align-items: center;\n}\n\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n\n.input-group-addon,\n.input-group-btn {\n white-space: nowrap;\n vertical-align: middle;\n}\n\n.input-group-addon {\n padding: 0.5rem 0.75rem;\n margin-bottom: 0;\n font-size: 1rem;\n font-weight: normal;\n line-height: 1.25;\n color: #495057;\n text-align: center;\n background-color: #e9ecef;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 0.25rem;\n}\n\n.input-group-addon.form-control-sm,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .input-group-addon.btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n border-radius: 0.2rem;\n}\n\n.input-group-addon.form-control-lg,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .input-group-addon.btn {\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n border-radius: 0.3rem;\n}\n\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n margin-top: 0;\n}\n\n.input-group .form-control:not(:last-child),\n.input-group-addon:not(:last-child),\n.input-group-btn:not(:last-child) > .btn,\n.input-group-btn:not(:last-child) > .btn-group > .btn,\n.input-group-btn:not(:last-child) > .dropdown-toggle,\n.input-group-btn:not(:first-child) > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:not(:first-child) > .btn-group:not(:last-child) > .btn {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n.input-group-addon:not(:last-child) {\n border-right: 0;\n}\n\n.input-group .form-control:not(:first-child),\n.input-group-addon:not(:first-child),\n.input-group-btn:not(:first-child) > .btn,\n.input-group-btn:not(:first-child) > .btn-group > .btn,\n.input-group-btn:not(:first-child) > .dropdown-toggle,\n.input-group-btn:not(:last-child) > .btn:not(:first-child),\n.input-group-btn:not(:last-child) > .btn-group:not(:first-child) > .btn {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.form-control + .input-group-addon:not(:first-child) {\n border-left: 0;\n}\n\n.input-group-btn {\n position: relative;\n font-size: 0;\n white-space: nowrap;\n}\n\n.input-group-btn > .btn {\n position: relative;\n}\n\n.input-group-btn > .btn + .btn {\n margin-left: -1px;\n}\n\n.input-group-btn > .btn:focus, .input-group-btn > .btn:active, .input-group-btn > .btn:hover {\n z-index: 3;\n}\n\n.input-group-btn:not(:last-child) > .btn,\n.input-group-btn:not(:last-child) > .btn-group {\n margin-right: -1px;\n}\n\n.input-group-btn:not(:first-child) > .btn,\n.input-group-btn:not(:first-child) > .btn-group {\n z-index: 2;\n margin-left: -1px;\n}\n\n.input-group-btn:not(:first-child) > .btn:focus, .input-group-btn:not(:first-child) > .btn:active, .input-group-btn:not(:first-child) > .btn:hover,\n.input-group-btn:not(:first-child) > .btn-group:focus,\n.input-group-btn:not(:first-child) > .btn-group:active,\n.input-group-btn:not(:first-child) > .btn-group:hover {\n z-index: 3;\n}\n\n.custom-control {\n position: relative;\n display: inline-flex;\n min-height: 1.5rem;\n padding-left: 1.5rem;\n margin-right: 1rem;\n}\n\n.custom-control-input {\n position: absolute;\n z-index: -1;\n opacity: 0;\n}\n\n.custom-control-input:checked ~ .custom-control-indicator {\n color: #fff;\n background-color: #007bff;\n}\n\n.custom-control-input:focus ~ .custom-control-indicator {\n box-shadow: 0 0 0 1px #fff, 0 0 0 3px #007bff;\n}\n\n.custom-control-input:active ~ .custom-control-indicator {\n color: #fff;\n background-color: #b3d7ff;\n}\n\n.custom-control-input:disabled ~ .custom-control-indicator {\n background-color: #e9ecef;\n}\n\n.custom-control-input:disabled ~ .custom-control-description {\n color: #868e96;\n}\n\n.custom-control-indicator {\n position: absolute;\n top: 0.25rem;\n left: 0;\n display: block;\n width: 1rem;\n height: 1rem;\n pointer-events: none;\n user-select: none;\n background-color: #ddd;\n background-repeat: no-repeat;\n background-position: center center;\n background-size: 50% 50%;\n}\n\n.custom-checkbox .custom-control-indicator {\n border-radius: 0.25rem;\n}\n\n.custom-checkbox .custom-control-input:checked ~ .custom-control-indicator {\n background-image: url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E\");\n}\n\n.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-indicator {\n background-color: #007bff;\n background-image: url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E\");\n}\n\n.custom-radio .custom-control-indicator {\n border-radius: 50%;\n}\n\n.custom-radio .custom-control-input:checked ~ .custom-control-indicator {\n background-image: url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E\");\n}\n\n.custom-controls-stacked {\n display: flex;\n flex-direction: column;\n}\n\n.custom-controls-stacked .custom-control {\n margin-bottom: 0.25rem;\n}\n\n.custom-controls-stacked .custom-control + .custom-control {\n margin-left: 0;\n}\n\n.custom-select {\n display: inline-block;\n max-width: 100%;\n height: calc(2.25rem + 2px);\n padding: 0.375rem 1.75rem 0.375rem 0.75rem;\n line-height: 1.25;\n color: #495057;\n vertical-align: middle;\n background: #fff url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23333' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E\") no-repeat right 0.75rem center;\n background-size: 8px 10px;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 0.25rem;\n appearance: none;\n}\n\n.custom-select:focus {\n border-color: #80bdff;\n outline: none;\n}\n\n.custom-select:focus::-ms-value {\n color: #495057;\n background-color: #fff;\n}\n\n.custom-select:disabled {\n color: #868e96;\n background-color: #e9ecef;\n}\n\n.custom-select::-ms-expand {\n opacity: 0;\n}\n\n.custom-select-sm {\n height: calc(1.8125rem + 2px);\n padding-top: 0.375rem;\n padding-bottom: 0.375rem;\n font-size: 75%;\n}\n\n.custom-file {\n position: relative;\n display: inline-block;\n max-width: 100%;\n height: 2.5rem;\n margin-bottom: 0;\n}\n\n.custom-file-input {\n min-width: 14rem;\n max-width: 100%;\n height: 2.5rem;\n margin: 0;\n opacity: 0;\n}\n\n.custom-file-control {\n position: absolute;\n top: 0;\n right: 0;\n left: 0;\n z-index: 5;\n height: 2.5rem;\n padding: 0.5rem 1rem;\n line-height: 1.5;\n color: #495057;\n pointer-events: none;\n user-select: none;\n background-color: #fff;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 0.25rem;\n}\n\n.custom-file-control:lang(en):empty::after {\n content: \"Choose file...\";\n}\n\n.custom-file-control::before {\n position: absolute;\n top: -1px;\n right: -1px;\n bottom: -1px;\n z-index: 6;\n display: block;\n height: 2.5rem;\n padding: 0.5rem 1rem;\n line-height: 1.5;\n color: #495057;\n background-color: #e9ecef;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 0 0.25rem 0.25rem 0;\n}\n\n.custom-file-control:lang(en)::before {\n content: \"Browse\";\n}\n\n.nav {\n display: flex;\n flex-wrap: wrap;\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n\n.nav-link {\n display: block;\n padding: 0.5rem 1rem;\n}\n\n.nav-link:focus, .nav-link:hover {\n text-decoration: none;\n}\n\n.nav-link.disabled {\n color: #868e96;\n}\n\n.nav-tabs {\n border-bottom: 1px solid #ddd;\n}\n\n.nav-tabs .nav-item {\n margin-bottom: -1px;\n}\n\n.nav-tabs .nav-link {\n border: 1px solid transparent;\n border-top-left-radius: 0.25rem;\n border-top-right-radius: 0.25rem;\n}\n\n.nav-tabs .nav-link:focus, .nav-tabs .nav-link:hover {\n border-color: #e9ecef #e9ecef #ddd;\n}\n\n.nav-tabs .nav-link.disabled {\n color: #868e96;\n background-color: transparent;\n border-color: transparent;\n}\n\n.nav-tabs .nav-link.active,\n.nav-tabs .nav-item.show .nav-link {\n color: #495057;\n background-color: #fff;\n border-color: #ddd #ddd #fff;\n}\n\n.nav-tabs .dropdown-menu {\n margin-top: -1px;\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n\n.nav-pills .nav-link {\n border-radius: 0.25rem;\n}\n\n.nav-pills .nav-link.active,\n.show > .nav-pills .nav-link {\n color: #fff;\n background-color: #007bff;\n}\n\n.nav-fill .nav-item {\n flex: 1 1 auto;\n text-align: center;\n}\n\n.nav-justified .nav-item {\n flex-basis: 0;\n flex-grow: 1;\n text-align: center;\n}\n\n.tab-content > .tab-pane {\n display: none;\n}\n\n.tab-content > .active {\n display: block;\n}\n\n.navbar {\n position: relative;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 1rem;\n}\n\n.navbar > .container,\n.navbar > .container-fluid {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n}\n\n@media (max-width: 575px) {\n .navbar > .container,\n .navbar > .container-fluid {\n width: 100%;\n margin-right: 0;\n margin-left: 0;\n }\n}\n\n.navbar-brand {\n display: inline-block;\n padding-top: 0.3125rem;\n padding-bottom: 0.3125rem;\n margin-right: 1rem;\n font-size: 1.25rem;\n line-height: inherit;\n white-space: nowrap;\n}\n\n.navbar-brand:focus, .navbar-brand:hover {\n text-decoration: none;\n}\n\n.navbar-nav {\n display: flex;\n flex-direction: column;\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n\n.navbar-nav .nav-link {\n padding-right: 0;\n padding-left: 0;\n}\n\n.navbar-nav .dropdown-menu {\n position: static;\n float: none;\n}\n\n.navbar-text {\n display: inline-block;\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n}\n\n.navbar-collapse {\n flex-basis: 100%;\n}\n\n.navbar-toggler {\n padding: 0.25rem 0.75rem;\n font-size: 1.25rem;\n line-height: 1;\n background: transparent;\n border: 1px solid transparent;\n border-radius: 0.25rem;\n}\n\n.navbar-toggler:focus, .navbar-toggler:hover {\n text-decoration: none;\n}\n\n.navbar-toggler-icon {\n display: inline-block;\n width: 1.5em;\n height: 1.5em;\n vertical-align: middle;\n content: \"\";\n background: no-repeat center center;\n background-size: 100% 100%;\n}\n\n@media (max-width: 575px) {\n .navbar-expand-sm > .container,\n .navbar-expand-sm > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n@media (min-width: 576px) {\n .navbar-expand-sm {\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-sm .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-sm .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-sm .navbar-nav .dropdown-menu-right {\n right: 0;\n left: auto;\n }\n .navbar-expand-sm .navbar-nav .nav-link {\n padding-right: .5rem;\n padding-left: .5rem;\n }\n .navbar-expand-sm > .container,\n .navbar-expand-sm > .container-fluid {\n flex-wrap: nowrap;\n }\n .navbar-expand-sm .navbar-collapse {\n display: flex !important;\n }\n .navbar-expand-sm .navbar-toggler {\n display: none;\n }\n}\n\n@media (max-width: 767px) {\n .navbar-expand-md > .container,\n .navbar-expand-md > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n@media (min-width: 768px) {\n .navbar-expand-md {\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-md .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-md .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-md .navbar-nav .dropdown-menu-right {\n right: 0;\n left: auto;\n }\n .navbar-expand-md .navbar-nav .nav-link {\n padding-right: .5rem;\n padding-left: .5rem;\n }\n .navbar-expand-md > .container,\n .navbar-expand-md > .container-fluid {\n flex-wrap: nowrap;\n }\n .navbar-expand-md .navbar-collapse {\n display: flex !important;\n }\n .navbar-expand-md .navbar-toggler {\n display: none;\n }\n}\n\n@media (max-width: 991px) {\n .navbar-expand-lg > .container,\n .navbar-expand-lg > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n@media (min-width: 992px) {\n .navbar-expand-lg {\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-lg .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-lg .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-lg .navbar-nav .dropdown-menu-right {\n right: 0;\n left: auto;\n }\n .navbar-expand-lg .navbar-nav .nav-link {\n padding-right: .5rem;\n padding-left: .5rem;\n }\n .navbar-expand-lg > .container,\n .navbar-expand-lg > .container-fluid {\n flex-wrap: nowrap;\n }\n .navbar-expand-lg .navbar-collapse {\n display: flex !important;\n }\n .navbar-expand-lg .navbar-toggler {\n display: none;\n }\n}\n\n@media (max-width: 1199px) {\n .navbar-expand-xl > .container,\n .navbar-expand-xl > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n@media (min-width: 1200px) {\n .navbar-expand-xl {\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-xl .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-xl .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-xl .navbar-nav .dropdown-menu-right {\n right: 0;\n left: auto;\n }\n .navbar-expand-xl .navbar-nav .nav-link {\n padding-right: .5rem;\n padding-left: .5rem;\n }\n .navbar-expand-xl > .container,\n .navbar-expand-xl > .container-fluid {\n flex-wrap: nowrap;\n }\n .navbar-expand-xl .navbar-collapse {\n display: flex !important;\n }\n .navbar-expand-xl .navbar-toggler {\n display: none;\n }\n}\n\n.navbar-expand {\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n}\n\n.navbar-expand > .container,\n.navbar-expand > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n}\n\n.navbar-expand .navbar-nav {\n flex-direction: row;\n}\n\n.navbar-expand .navbar-nav .dropdown-menu {\n position: absolute;\n}\n\n.navbar-expand .navbar-nav .dropdown-menu-right {\n right: 0;\n left: auto;\n}\n\n.navbar-expand .navbar-nav .nav-link {\n padding-right: .5rem;\n padding-left: .5rem;\n}\n\n.navbar-expand > .container,\n.navbar-expand > .container-fluid {\n flex-wrap: nowrap;\n}\n\n.navbar-expand .navbar-collapse {\n display: flex !important;\n}\n\n.navbar-expand .navbar-toggler {\n display: none;\n}\n\n.navbar-light .navbar-brand {\n color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-light .navbar-brand:focus, .navbar-light .navbar-brand:hover {\n color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-light .navbar-nav .nav-link {\n color: rgba(0, 0, 0, 0.5);\n}\n\n.navbar-light .navbar-nav .nav-link:focus, .navbar-light .navbar-nav .nav-link:hover {\n color: rgba(0, 0, 0, 0.7);\n}\n\n.navbar-light .navbar-nav .nav-link.disabled {\n color: rgba(0, 0, 0, 0.3);\n}\n\n.navbar-light .navbar-nav .show > .nav-link,\n.navbar-light .navbar-nav .active > .nav-link,\n.navbar-light .navbar-nav .nav-link.show,\n.navbar-light .navbar-nav .nav-link.active {\n color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-light .navbar-toggler {\n color: rgba(0, 0, 0, 0.5);\n border-color: rgba(0, 0, 0, 0.1);\n}\n\n.navbar-light .navbar-toggler-icon {\n background-image: url(\"data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E\");\n}\n\n.navbar-light .navbar-text {\n color: rgba(0, 0, 0, 0.5);\n}\n\n.navbar-dark .navbar-brand {\n color: white;\n}\n\n.navbar-dark .navbar-brand:focus, .navbar-dark .navbar-brand:hover {\n color: white;\n}\n\n.navbar-dark .navbar-nav .nav-link {\n color: rgba(255, 255, 255, 0.5);\n}\n\n.navbar-dark .navbar-nav .nav-link:focus, .navbar-dark .navbar-nav .nav-link:hover {\n color: rgba(255, 255, 255, 0.75);\n}\n\n.navbar-dark .navbar-nav .nav-link.disabled {\n color: rgba(255, 255, 255, 0.25);\n}\n\n.navbar-dark .navbar-nav .show > .nav-link,\n.navbar-dark .navbar-nav .active > .nav-link,\n.navbar-dark .navbar-nav .nav-link.show,\n.navbar-dark .navbar-nav .nav-link.active {\n color: white;\n}\n\n.navbar-dark .navbar-toggler {\n color: rgba(255, 255, 255, 0.5);\n border-color: rgba(255, 255, 255, 0.1);\n}\n\n.navbar-dark .navbar-toggler-icon {\n background-image: url(\"data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E\");\n}\n\n.navbar-dark .navbar-text {\n color: rgba(255, 255, 255, 0.5);\n}\n\n.card {\n position: relative;\n display: flex;\n flex-direction: column;\n min-width: 0;\n word-wrap: break-word;\n background-color: #fff;\n background-clip: border-box;\n border: 1px solid rgba(0, 0, 0, 0.125);\n border-radius: 0.25rem;\n}\n\n.card-body {\n flex: 1 1 auto;\n padding: 1.25rem;\n}\n\n.card-title {\n margin-bottom: 0.75rem;\n}\n\n.card-subtitle {\n margin-top: -0.375rem;\n margin-bottom: 0;\n}\n\n.card-text:last-child {\n margin-bottom: 0;\n}\n\n.card-link:hover {\n text-decoration: none;\n}\n\n.card-link + .card-link {\n margin-left: 1.25rem;\n}\n\n.card > .list-group:first-child .list-group-item:first-child {\n border-top-left-radius: 0.25rem;\n border-top-right-radius: 0.25rem;\n}\n\n.card > .list-group:last-child .list-group-item:last-child {\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n}\n\n.card-header {\n padding: 0.75rem 1.25rem;\n margin-bottom: 0;\n background-color: rgba(0, 0, 0, 0.03);\n border-bottom: 1px solid rgba(0, 0, 0, 0.125);\n}\n\n.card-header:first-child {\n border-radius: calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0;\n}\n\n.card-footer {\n padding: 0.75rem 1.25rem;\n background-color: rgba(0, 0, 0, 0.03);\n border-top: 1px solid rgba(0, 0, 0, 0.125);\n}\n\n.card-footer:last-child {\n border-radius: 0 0 calc(0.25rem - 1px) calc(0.25rem - 1px);\n}\n\n.card-header-tabs {\n margin-right: -0.625rem;\n margin-bottom: -0.75rem;\n margin-left: -0.625rem;\n border-bottom: 0;\n}\n\n.card-header-pills {\n margin-right: -0.625rem;\n margin-left: -0.625rem;\n}\n\n.card-img-overlay {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n padding: 1.25rem;\n}\n\n.card-img {\n width: 100%;\n border-radius: calc(0.25rem - 1px);\n}\n\n.card-img-top {\n width: 100%;\n border-top-left-radius: calc(0.25rem - 1px);\n border-top-right-radius: calc(0.25rem - 1px);\n}\n\n.card-img-bottom {\n width: 100%;\n border-bottom-right-radius: calc(0.25rem - 1px);\n border-bottom-left-radius: calc(0.25rem - 1px);\n}\n\n@media (min-width: 576px) {\n .card-deck {\n display: flex;\n flex-flow: row wrap;\n margin-right: -15px;\n margin-left: -15px;\n }\n .card-deck .card {\n display: flex;\n flex: 1 0 0%;\n flex-direction: column;\n margin-right: 15px;\n margin-left: 15px;\n }\n}\n\n@media (min-width: 576px) {\n .card-group {\n display: flex;\n flex-flow: row wrap;\n }\n .card-group .card {\n flex: 1 0 0%;\n }\n .card-group .card + .card {\n margin-left: 0;\n border-left: 0;\n }\n .card-group .card:first-child {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n }\n .card-group .card:first-child .card-img-top {\n border-top-right-radius: 0;\n }\n .card-group .card:first-child .card-img-bottom {\n border-bottom-right-radius: 0;\n }\n .card-group .card:last-child {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n }\n .card-group .card:last-child .card-img-top {\n border-top-left-radius: 0;\n }\n .card-group .card:last-child .card-img-bottom {\n border-bottom-left-radius: 0;\n }\n .card-group .card:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n .card-group .card:not(:first-child):not(:last-child) .card-img-top,\n .card-group .card:not(:first-child):not(:last-child) .card-img-bottom {\n border-radius: 0;\n }\n}\n\n.card-columns .card {\n margin-bottom: 0.75rem;\n}\n\n@media (min-width: 576px) {\n .card-columns {\n column-count: 3;\n column-gap: 1.25rem;\n }\n .card-columns .card {\n display: inline-block;\n width: 100%;\n }\n}\n\n.breadcrumb {\n padding: 0.75rem 1rem;\n margin-bottom: 1rem;\n list-style: none;\n background-color: #e9ecef;\n border-radius: 0.25rem;\n}\n\n.breadcrumb::after {\n display: block;\n clear: both;\n content: \"\";\n}\n\n.breadcrumb-item {\n float: left;\n}\n\n.breadcrumb-item + .breadcrumb-item::before {\n display: inline-block;\n padding-right: 0.5rem;\n padding-left: 0.5rem;\n color: #868e96;\n content: \"/\";\n}\n\n.breadcrumb-item + .breadcrumb-item:hover::before {\n text-decoration: underline;\n}\n\n.breadcrumb-item + .breadcrumb-item:hover::before {\n text-decoration: none;\n}\n\n.breadcrumb-item.active {\n color: #868e96;\n}\n\n.pagination {\n display: flex;\n padding-left: 0;\n list-style: none;\n border-radius: 0.25rem;\n}\n\n.page-item:first-child .page-link {\n margin-left: 0;\n border-top-left-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n}\n\n.page-item:last-child .page-link {\n border-top-right-radius: 0.25rem;\n border-bottom-right-radius: 0.25rem;\n}\n\n.page-item.active .page-link {\n z-index: 2;\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.page-item.disabled .page-link {\n color: #868e96;\n pointer-events: none;\n background-color: #fff;\n border-color: #ddd;\n}\n\n.page-link {\n position: relative;\n display: block;\n padding: 0.5rem 0.75rem;\n margin-left: -1px;\n line-height: 1.25;\n color: #007bff;\n background-color: #fff;\n border: 1px solid #ddd;\n}\n\n.page-link:focus, .page-link:hover {\n color: #0056b3;\n text-decoration: none;\n background-color: #e9ecef;\n border-color: #ddd;\n}\n\n.pagination-lg .page-link {\n padding: 0.75rem 1.5rem;\n font-size: 1.25rem;\n line-height: 1.5;\n}\n\n.pagination-lg .page-item:first-child .page-link {\n border-top-left-radius: 0.3rem;\n border-bottom-left-radius: 0.3rem;\n}\n\n.pagination-lg .page-item:last-child .page-link {\n border-top-right-radius: 0.3rem;\n border-bottom-right-radius: 0.3rem;\n}\n\n.pagination-sm .page-link {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n line-height: 1.5;\n}\n\n.pagination-sm .page-item:first-child .page-link {\n border-top-left-radius: 0.2rem;\n border-bottom-left-radius: 0.2rem;\n}\n\n.pagination-sm .page-item:last-child .page-link {\n border-top-right-radius: 0.2rem;\n border-bottom-right-radius: 0.2rem;\n}\n\n.badge {\n display: inline-block;\n padding: 0.25em 0.4em;\n font-size: 75%;\n font-weight: bold;\n line-height: 1;\n color: #fff;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: 0.25rem;\n}\n\n.badge:empty {\n display: none;\n}\n\n.btn .badge {\n position: relative;\n top: -1px;\n}\n\n.badge-pill {\n padding-right: 0.6em;\n padding-left: 0.6em;\n border-radius: 10rem;\n}\n\n.badge-primary {\n color: #fff;\n background-color: #007bff;\n}\n\n.badge-primary[href]:focus, .badge-primary[href]:hover {\n color: #fff;\n text-decoration: none;\n background-color: #0062cc;\n}\n\n.badge-secondary {\n color: #fff;\n background-color: #868e96;\n}\n\n.badge-secondary[href]:focus, .badge-secondary[href]:hover {\n color: #fff;\n text-decoration: none;\n background-color: #6c757d;\n}\n\n.badge-success {\n color: #fff;\n background-color: #28a745;\n}\n\n.badge-success[href]:focus, .badge-success[href]:hover {\n color: #fff;\n text-decoration: none;\n background-color: #1e7e34;\n}\n\n.badge-info {\n color: #fff;\n background-color: #17a2b8;\n}\n\n.badge-info[href]:focus, .badge-info[href]:hover {\n color: #fff;\n text-decoration: none;\n background-color: #117a8b;\n}\n\n.badge-warning {\n color: #111;\n background-color: #ffc107;\n}\n\n.badge-warning[href]:focus, .badge-warning[href]:hover {\n color: #111;\n text-decoration: none;\n background-color: #d39e00;\n}\n\n.badge-danger {\n color: #fff;\n background-color: #dc3545;\n}\n\n.badge-danger[href]:focus, .badge-danger[href]:hover {\n color: #fff;\n text-decoration: none;\n background-color: #bd2130;\n}\n\n.badge-light {\n color: #111;\n background-color: #f8f9fa;\n}\n\n.badge-light[href]:focus, .badge-light[href]:hover {\n color: #111;\n text-decoration: none;\n background-color: #dae0e5;\n}\n\n.badge-dark {\n color: #fff;\n background-color: #343a40;\n}\n\n.badge-dark[href]:focus, .badge-dark[href]:hover {\n color: #fff;\n text-decoration: none;\n background-color: #1d2124;\n}\n\n.jumbotron {\n padding: 2rem 1rem;\n margin-bottom: 2rem;\n background-color: #e9ecef;\n border-radius: 0.3rem;\n}\n\n@media (min-width: 576px) {\n .jumbotron {\n padding: 4rem 2rem;\n }\n}\n\n.jumbotron-fluid {\n padding-right: 0;\n padding-left: 0;\n border-radius: 0;\n}\n\n.alert {\n padding: 0.75rem 1.25rem;\n margin-bottom: 1rem;\n border: 1px solid transparent;\n border-radius: 0.25rem;\n}\n\n.alert-heading {\n color: inherit;\n}\n\n.alert-link {\n font-weight: bold;\n}\n\n.alert-dismissible .close {\n position: relative;\n top: -0.75rem;\n right: -1.25rem;\n padding: 0.75rem 1.25rem;\n color: inherit;\n}\n\n.alert-primary {\n color: #004085;\n background-color: #cce5ff;\n border-color: #b8daff;\n}\n\n.alert-primary hr {\n border-top-color: #9fcdff;\n}\n\n.alert-primary .alert-link {\n color: #002752;\n}\n\n.alert-secondary {\n color: #464a4e;\n background-color: #e7e8ea;\n border-color: #dddfe2;\n}\n\n.alert-secondary hr {\n border-top-color: #cfd2d6;\n}\n\n.alert-secondary .alert-link {\n color: #2e3133;\n}\n\n.alert-success {\n color: #155724;\n background-color: #d4edda;\n border-color: #c3e6cb;\n}\n\n.alert-success hr {\n border-top-color: #b1dfbb;\n}\n\n.alert-success .alert-link {\n color: #0b2e13;\n}\n\n.alert-info {\n color: #0c5460;\n background-color: #d1ecf1;\n border-color: #bee5eb;\n}\n\n.alert-info hr {\n border-top-color: #abdde5;\n}\n\n.alert-info .alert-link {\n color: #062c33;\n}\n\n.alert-warning {\n color: #856404;\n background-color: #fff3cd;\n border-color: #ffeeba;\n}\n\n.alert-warning hr {\n border-top-color: #ffe8a1;\n}\n\n.alert-warning .alert-link {\n color: #533f03;\n}\n\n.alert-danger {\n color: #721c24;\n background-color: #f8d7da;\n border-color: #f5c6cb;\n}\n\n.alert-danger hr {\n border-top-color: #f1b0b7;\n}\n\n.alert-danger .alert-link {\n color: #491217;\n}\n\n.alert-light {\n color: #818182;\n background-color: #fefefe;\n border-color: #fdfdfe;\n}\n\n.alert-light hr {\n border-top-color: #ececf6;\n}\n\n.alert-light .alert-link {\n color: #686868;\n}\n\n.alert-dark {\n color: #1b1e21;\n background-color: #d6d8d9;\n border-color: #c6c8ca;\n}\n\n.alert-dark hr {\n border-top-color: #b9bbbe;\n}\n\n.alert-dark .alert-link {\n color: #040505;\n}\n\n@keyframes progress-bar-stripes {\n from {\n background-position: 1rem 0;\n }\n to {\n background-position: 0 0;\n }\n}\n\n.progress {\n display: flex;\n overflow: hidden;\n font-size: 0.75rem;\n line-height: 1rem;\n text-align: center;\n background-color: #e9ecef;\n border-radius: 0.25rem;\n}\n\n.progress-bar {\n height: 1rem;\n line-height: 1rem;\n color: #fff;\n background-color: #007bff;\n transition: width 0.6s ease;\n}\n\n.progress-bar-striped {\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-size: 1rem 1rem;\n}\n\n.progress-bar-animated {\n animation: progress-bar-stripes 1s linear infinite;\n}\n\n.media {\n display: flex;\n align-items: flex-start;\n}\n\n.media-body {\n flex: 1;\n}\n\n.list-group {\n display: flex;\n flex-direction: column;\n padding-left: 0;\n margin-bottom: 0;\n}\n\n.list-group-item-action {\n width: 100%;\n color: #495057;\n text-align: inherit;\n}\n\n.list-group-item-action:focus, .list-group-item-action:hover {\n color: #495057;\n text-decoration: none;\n background-color: #f8f9fa;\n}\n\n.list-group-item-action:active {\n color: #212529;\n background-color: #e9ecef;\n}\n\n.list-group-item {\n position: relative;\n display: block;\n padding: 0.75rem 1.25rem;\n margin-bottom: -1px;\n background-color: #fff;\n border: 1px solid rgba(0, 0, 0, 0.125);\n}\n\n.list-group-item:first-child {\n border-top-left-radius: 0.25rem;\n border-top-right-radius: 0.25rem;\n}\n\n.list-group-item:last-child {\n margin-bottom: 0;\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n}\n\n.list-group-item:focus, .list-group-item:hover {\n text-decoration: none;\n}\n\n.list-group-item.disabled, .list-group-item:disabled {\n color: #868e96;\n background-color: #fff;\n}\n\n.list-group-item.active {\n z-index: 2;\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.list-group-flush .list-group-item {\n border-right: 0;\n border-left: 0;\n border-radius: 0;\n}\n\n.list-group-flush:first-child .list-group-item:first-child {\n border-top: 0;\n}\n\n.list-group-flush:last-child .list-group-item:last-child {\n border-bottom: 0;\n}\n\n.list-group-item-primary {\n color: #004085;\n background-color: #b8daff;\n}\n\na.list-group-item-primary,\nbutton.list-group-item-primary {\n color: #004085;\n}\n\na.list-group-item-primary:focus, a.list-group-item-primary:hover,\nbutton.list-group-item-primary:focus,\nbutton.list-group-item-primary:hover {\n color: #004085;\n background-color: #9fcdff;\n}\n\na.list-group-item-primary.active,\nbutton.list-group-item-primary.active {\n color: #fff;\n background-color: #004085;\n border-color: #004085;\n}\n\n.list-group-item-secondary {\n color: #464a4e;\n background-color: #dddfe2;\n}\n\na.list-group-item-secondary,\nbutton.list-group-item-secondary {\n color: #464a4e;\n}\n\na.list-group-item-secondary:focus, a.list-group-item-secondary:hover,\nbutton.list-group-item-secondary:focus,\nbutton.list-group-item-secondary:hover {\n color: #464a4e;\n background-color: #cfd2d6;\n}\n\na.list-group-item-secondary.active,\nbutton.list-group-item-secondary.active {\n color: #fff;\n background-color: #464a4e;\n border-color: #464a4e;\n}\n\n.list-group-item-success {\n color: #155724;\n background-color: #c3e6cb;\n}\n\na.list-group-item-success,\nbutton.list-group-item-success {\n color: #155724;\n}\n\na.list-group-item-success:focus, a.list-group-item-success:hover,\nbutton.list-group-item-success:focus,\nbutton.list-group-item-success:hover {\n color: #155724;\n background-color: #b1dfbb;\n}\n\na.list-group-item-success.active,\nbutton.list-group-item-success.active {\n color: #fff;\n background-color: #155724;\n border-color: #155724;\n}\n\n.list-group-item-info {\n color: #0c5460;\n background-color: #bee5eb;\n}\n\na.list-group-item-info,\nbutton.list-group-item-info {\n color: #0c5460;\n}\n\na.list-group-item-info:focus, a.list-group-item-info:hover,\nbutton.list-group-item-info:focus,\nbutton.list-group-item-info:hover {\n color: #0c5460;\n background-color: #abdde5;\n}\n\na.list-group-item-info.active,\nbutton.list-group-item-info.active {\n color: #fff;\n background-color: #0c5460;\n border-color: #0c5460;\n}\n\n.list-group-item-warning {\n color: #856404;\n background-color: #ffeeba;\n}\n\na.list-group-item-warning,\nbutton.list-group-item-warning {\n color: #856404;\n}\n\na.list-group-item-warning:focus, a.list-group-item-warning:hover,\nbutton.list-group-item-warning:focus,\nbutton.list-group-item-warning:hover {\n color: #856404;\n background-color: #ffe8a1;\n}\n\na.list-group-item-warning.active,\nbutton.list-group-item-warning.active {\n color: #fff;\n background-color: #856404;\n border-color: #856404;\n}\n\n.list-group-item-danger {\n color: #721c24;\n background-color: #f5c6cb;\n}\n\na.list-group-item-danger,\nbutton.list-group-item-danger {\n color: #721c24;\n}\n\na.list-group-item-danger:focus, a.list-group-item-danger:hover,\nbutton.list-group-item-danger:focus,\nbutton.list-group-item-danger:hover {\n color: #721c24;\n background-color: #f1b0b7;\n}\n\na.list-group-item-danger.active,\nbutton.list-group-item-danger.active {\n color: #fff;\n background-color: #721c24;\n border-color: #721c24;\n}\n\n.list-group-item-light {\n color: #818182;\n background-color: #fdfdfe;\n}\n\na.list-group-item-light,\nbutton.list-group-item-light {\n color: #818182;\n}\n\na.list-group-item-light:focus, a.list-group-item-light:hover,\nbutton.list-group-item-light:focus,\nbutton.list-group-item-light:hover {\n color: #818182;\n background-color: #ececf6;\n}\n\na.list-group-item-light.active,\nbutton.list-group-item-light.active {\n color: #fff;\n background-color: #818182;\n border-color: #818182;\n}\n\n.list-group-item-dark {\n color: #1b1e21;\n background-color: #c6c8ca;\n}\n\na.list-group-item-dark,\nbutton.list-group-item-dark {\n color: #1b1e21;\n}\n\na.list-group-item-dark:focus, a.list-group-item-dark:hover,\nbutton.list-group-item-dark:focus,\nbutton.list-group-item-dark:hover {\n color: #1b1e21;\n background-color: #b9bbbe;\n}\n\na.list-group-item-dark.active,\nbutton.list-group-item-dark.active {\n color: #fff;\n background-color: #1b1e21;\n border-color: #1b1e21;\n}\n\n.close {\n float: right;\n font-size: 1.5rem;\n font-weight: bold;\n line-height: 1;\n color: #000;\n text-shadow: 0 1px 0 #fff;\n opacity: .5;\n}\n\n.close:focus, .close:hover {\n color: #000;\n text-decoration: none;\n opacity: .75;\n}\n\nbutton.close {\n padding: 0;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n}\n\n.modal-open {\n overflow: hidden;\n}\n\n.modal {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1050;\n display: none;\n overflow: hidden;\n outline: 0;\n}\n\n.modal.fade .modal-dialog {\n transition: transform 0.3s ease-out;\n transform: translate(0, -25%);\n}\n\n.modal.show .modal-dialog {\n transform: translate(0, 0);\n}\n\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n\n.modal-content {\n position: relative;\n display: flex;\n flex-direction: column;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 0.3rem;\n outline: 0;\n}\n\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1040;\n background-color: #000;\n}\n\n.modal-backdrop.fade {\n opacity: 0;\n}\n\n.modal-backdrop.show {\n opacity: 0.5;\n}\n\n.modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 15px;\n border-bottom: 1px solid #e9ecef;\n}\n\n.modal-title {\n margin-bottom: 0;\n line-height: 1.5;\n}\n\n.modal-body {\n position: relative;\n flex: 1 1 auto;\n padding: 15px;\n}\n\n.modal-footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n padding: 15px;\n border-top: 1px solid #e9ecef;\n}\n\n.modal-footer > :not(:first-child) {\n margin-left: .25rem;\n}\n\n.modal-footer > :not(:last-child) {\n margin-right: .25rem;\n}\n\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n\n@media (min-width: 576px) {\n .modal-dialog {\n max-width: 500px;\n margin: 30px auto;\n }\n .modal-sm {\n max-width: 300px;\n }\n}\n\n@media (min-width: 992px) {\n .modal-lg {\n max-width: 800px;\n }\n}\n\n.tooltip {\n position: absolute;\n z-index: 1070;\n display: block;\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n font-style: normal;\n font-weight: normal;\n line-height: 1.5;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n white-space: normal;\n line-break: auto;\n font-size: 0.875rem;\n word-wrap: break-word;\n opacity: 0;\n}\n\n.tooltip.show {\n opacity: 0.9;\n}\n\n.tooltip .arrow {\n position: absolute;\n display: block;\n width: 5px;\n height: 5px;\n}\n\n.tooltip.bs-tooltip-top, .tooltip.bs-tooltip-auto[x-placement^=\"top\"] {\n padding: 5px 0;\n}\n\n.tooltip.bs-tooltip-top .arrow, .tooltip.bs-tooltip-auto[x-placement^=\"top\"] .arrow {\n bottom: 0;\n}\n\n.tooltip.bs-tooltip-top .arrow::before, .tooltip.bs-tooltip-auto[x-placement^=\"top\"] .arrow::before {\n margin-left: -3px;\n content: \"\";\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n\n.tooltip.bs-tooltip-right, .tooltip.bs-tooltip-auto[x-placement^=\"right\"] {\n padding: 0 5px;\n}\n\n.tooltip.bs-tooltip-right .arrow, .tooltip.bs-tooltip-auto[x-placement^=\"right\"] .arrow {\n left: 0;\n}\n\n.tooltip.bs-tooltip-right .arrow::before, .tooltip.bs-tooltip-auto[x-placement^=\"right\"] .arrow::before {\n margin-top: -3px;\n content: \"\";\n border-width: 5px 5px 5px 0;\n border-right-color: #000;\n}\n\n.tooltip.bs-tooltip-bottom, .tooltip.bs-tooltip-auto[x-placement^=\"bottom\"] {\n padding: 5px 0;\n}\n\n.tooltip.bs-tooltip-bottom .arrow, .tooltip.bs-tooltip-auto[x-placement^=\"bottom\"] .arrow {\n top: 0;\n}\n\n.tooltip.bs-tooltip-bottom .arrow::before, .tooltip.bs-tooltip-auto[x-placement^=\"bottom\"] .arrow::before {\n margin-left: -3px;\n content: \"\";\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n\n.tooltip.bs-tooltip-left, .tooltip.bs-tooltip-auto[x-placement^=\"left\"] {\n padding: 0 5px;\n}\n\n.tooltip.bs-tooltip-left .arrow, .tooltip.bs-tooltip-auto[x-placement^=\"left\"] .arrow {\n right: 0;\n}\n\n.tooltip.bs-tooltip-left .arrow::before, .tooltip.bs-tooltip-auto[x-placement^=\"left\"] .arrow::before {\n right: 0;\n margin-top: -3px;\n content: \"\";\n border-width: 5px 0 5px 5px;\n border-left-color: #000;\n}\n\n.tooltip .arrow::before {\n position: absolute;\n border-color: transparent;\n border-style: solid;\n}\n\n.tooltip-inner {\n max-width: 200px;\n padding: 3px 8px;\n color: #fff;\n text-align: center;\n background-color: #000;\n border-radius: 0.25rem;\n}\n\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1060;\n display: block;\n max-width: 276px;\n padding: 1px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n font-style: normal;\n font-weight: normal;\n line-height: 1.5;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n white-space: normal;\n line-break: auto;\n font-size: 0.875rem;\n word-wrap: break-word;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 0.3rem;\n}\n\n.popover .arrow {\n position: absolute;\n display: block;\n width: 10px;\n height: 5px;\n}\n\n.popover .arrow::before,\n.popover .arrow::after {\n position: absolute;\n display: block;\n border-color: transparent;\n border-style: solid;\n}\n\n.popover .arrow::before {\n content: \"\";\n border-width: 11px;\n}\n\n.popover .arrow::after {\n content: \"\";\n border-width: 11px;\n}\n\n.popover.bs-popover-top, .popover.bs-popover-auto[x-placement^=\"top\"] {\n margin-bottom: 10px;\n}\n\n.popover.bs-popover-top .arrow, .popover.bs-popover-auto[x-placement^=\"top\"] .arrow {\n bottom: 0;\n}\n\n.popover.bs-popover-top .arrow::before, .popover.bs-popover-auto[x-placement^=\"top\"] .arrow::before,\n.popover.bs-popover-top .arrow::after, .popover.bs-popover-auto[x-placement^=\"top\"] .arrow::after {\n border-bottom-width: 0;\n}\n\n.popover.bs-popover-top .arrow::before, .popover.bs-popover-auto[x-placement^=\"top\"] .arrow::before {\n bottom: -11px;\n margin-left: -6px;\n border-top-color: rgba(0, 0, 0, 0.25);\n}\n\n.popover.bs-popover-top .arrow::after, .popover.bs-popover-auto[x-placement^=\"top\"] .arrow::after {\n bottom: -10px;\n margin-left: -6px;\n border-top-color: #fff;\n}\n\n.popover.bs-popover-right, .popover.bs-popover-auto[x-placement^=\"right\"] {\n margin-left: 10px;\n}\n\n.popover.bs-popover-right .arrow, .popover.bs-popover-auto[x-placement^=\"right\"] .arrow {\n left: 0;\n}\n\n.popover.bs-popover-right .arrow::before, .popover.bs-popover-auto[x-placement^=\"right\"] .arrow::before,\n.popover.bs-popover-right .arrow::after, .popover.bs-popover-auto[x-placement^=\"right\"] .arrow::after {\n margin-top: -8px;\n border-left-width: 0;\n}\n\n.popover.bs-popover-right .arrow::before, .popover.bs-popover-auto[x-placement^=\"right\"] .arrow::before {\n left: -11px;\n border-right-color: rgba(0, 0, 0, 0.25);\n}\n\n.popover.bs-popover-right .arrow::after, .popover.bs-popover-auto[x-placement^=\"right\"] .arrow::after {\n left: -10px;\n border-right-color: #fff;\n}\n\n.popover.bs-popover-bottom, .popover.bs-popover-auto[x-placement^=\"bottom\"] {\n margin-top: 10px;\n}\n\n.popover.bs-popover-bottom .arrow, .popover.bs-popover-auto[x-placement^=\"bottom\"] .arrow {\n top: 0;\n}\n\n.popover.bs-popover-bottom .arrow::before, .popover.bs-popover-auto[x-placement^=\"bottom\"] .arrow::before,\n.popover.bs-popover-bottom .arrow::after, .popover.bs-popover-auto[x-placement^=\"bottom\"] .arrow::after {\n margin-left: -7px;\n border-top-width: 0;\n}\n\n.popover.bs-popover-bottom .arrow::before, .popover.bs-popover-auto[x-placement^=\"bottom\"] .arrow::before {\n top: -11px;\n border-bottom-color: rgba(0, 0, 0, 0.25);\n}\n\n.popover.bs-popover-bottom .arrow::after, .popover.bs-popover-auto[x-placement^=\"bottom\"] .arrow::after {\n top: -10px;\n border-bottom-color: #fff;\n}\n\n.popover.bs-popover-bottom .popover-header::before, .popover.bs-popover-auto[x-placement^=\"bottom\"] .popover-header::before {\n position: absolute;\n top: 0;\n left: 50%;\n display: block;\n width: 20px;\n margin-left: -10px;\n content: \"\";\n border-bottom: 1px solid #f7f7f7;\n}\n\n.popover.bs-popover-left, .popover.bs-popover-auto[x-placement^=\"left\"] {\n margin-right: 10px;\n}\n\n.popover.bs-popover-left .arrow, .popover.bs-popover-auto[x-placement^=\"left\"] .arrow {\n right: 0;\n}\n\n.popover.bs-popover-left .arrow::before, .popover.bs-popover-auto[x-placement^=\"left\"] .arrow::before,\n.popover.bs-popover-left .arrow::after, .popover.bs-popover-auto[x-placement^=\"left\"] .arrow::after {\n margin-top: -8px;\n border-right-width: 0;\n}\n\n.popover.bs-popover-left .arrow::before, .popover.bs-popover-auto[x-placement^=\"left\"] .arrow::before {\n right: -11px;\n border-left-color: rgba(0, 0, 0, 0.25);\n}\n\n.popover.bs-popover-left .arrow::after, .popover.bs-popover-auto[x-placement^=\"left\"] .arrow::after {\n right: -10px;\n border-left-color: #fff;\n}\n\n.popover-header {\n padding: 8px 14px;\n margin-bottom: 0;\n font-size: 1rem;\n color: inherit;\n background-color: #f7f7f7;\n border-bottom: 1px solid #ebebeb;\n border-top-left-radius: calc(0.3rem - 1px);\n border-top-right-radius: calc(0.3rem - 1px);\n}\n\n.popover-header:empty {\n display: none;\n}\n\n.popover-body {\n padding: 9px 14px;\n color: #212529;\n}\n\n.carousel {\n position: relative;\n}\n\n.carousel-inner {\n position: relative;\n width: 100%;\n overflow: hidden;\n}\n\n.carousel-item {\n position: relative;\n display: none;\n align-items: center;\n width: 100%;\n transition: transform 0.6s ease;\n backface-visibility: hidden;\n perspective: 1000px;\n}\n\n.carousel-item.active,\n.carousel-item-next,\n.carousel-item-prev {\n display: block;\n}\n\n.carousel-item-next,\n.carousel-item-prev {\n position: absolute;\n top: 0;\n}\n\n.carousel-item-next.carousel-item-left,\n.carousel-item-prev.carousel-item-right {\n transform: translateX(0);\n}\n\n@supports (transform-style: preserve-3d) {\n .carousel-item-next.carousel-item-left,\n .carousel-item-prev.carousel-item-right {\n transform: translate3d(0, 0, 0);\n }\n}\n\n.carousel-item-next,\n.active.carousel-item-right {\n transform: translateX(100%);\n}\n\n@supports (transform-style: preserve-3d) {\n .carousel-item-next,\n .active.carousel-item-right {\n transform: translate3d(100%, 0, 0);\n }\n}\n\n.carousel-item-prev,\n.active.carousel-item-left {\n transform: translateX(-100%);\n}\n\n@supports (transform-style: preserve-3d) {\n .carousel-item-prev,\n .active.carousel-item-left {\n transform: translate3d(-100%, 0, 0);\n }\n}\n\n.carousel-control-prev,\n.carousel-control-next {\n position: absolute;\n top: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 15%;\n color: #fff;\n text-align: center;\n opacity: 0.5;\n}\n\n.carousel-control-prev:focus, .carousel-control-prev:hover,\n.carousel-control-next:focus,\n.carousel-control-next:hover {\n color: #fff;\n text-decoration: none;\n outline: 0;\n opacity: .9;\n}\n\n.carousel-control-prev {\n left: 0;\n}\n\n.carousel-control-next {\n right: 0;\n}\n\n.carousel-control-prev-icon,\n.carousel-control-next-icon {\n display: inline-block;\n width: 20px;\n height: 20px;\n background: transparent no-repeat center center;\n background-size: 100% 100%;\n}\n\n.carousel-control-prev-icon {\n background-image: url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M4 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E\");\n}\n\n.carousel-control-next-icon {\n background-image: url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M1.5 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E\");\n}\n\n.carousel-indicators {\n position: absolute;\n right: 0;\n bottom: 10px;\n left: 0;\n z-index: 15;\n display: flex;\n justify-content: center;\n padding-left: 0;\n margin-right: 15%;\n margin-left: 15%;\n list-style: none;\n}\n\n.carousel-indicators li {\n position: relative;\n flex: 0 1 auto;\n width: 30px;\n height: 3px;\n margin-right: 3px;\n margin-left: 3px;\n text-indent: -999px;\n background-color: rgba(255, 255, 255, 0.5);\n}\n\n.carousel-indicators li::before {\n position: absolute;\n top: -10px;\n left: 0;\n display: inline-block;\n width: 100%;\n height: 10px;\n content: \"\";\n}\n\n.carousel-indicators li::after {\n position: absolute;\n bottom: -10px;\n left: 0;\n display: inline-block;\n width: 100%;\n height: 10px;\n content: \"\";\n}\n\n.carousel-indicators .active {\n background-color: #fff;\n}\n\n.carousel-caption {\n position: absolute;\n right: 15%;\n bottom: 20px;\n left: 15%;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: #fff;\n text-align: center;\n}\n\n.align-baseline {\n vertical-align: baseline !important;\n}\n\n.align-top {\n vertical-align: top !important;\n}\n\n.align-middle {\n vertical-align: middle !important;\n}\n\n.align-bottom {\n vertical-align: bottom !important;\n}\n\n.align-text-bottom {\n vertical-align: text-bottom !important;\n}\n\n.align-text-top {\n vertical-align: text-top !important;\n}\n\n.bg-primary {\n background-color: #007bff !important;\n}\n\na.bg-primary:focus, a.bg-primary:hover {\n background-color: #0062cc !important;\n}\n\n.bg-secondary {\n background-color: #868e96 !important;\n}\n\na.bg-secondary:focus, a.bg-secondary:hover {\n background-color: #6c757d !important;\n}\n\n.bg-success {\n background-color: #28a745 !important;\n}\n\na.bg-success:focus, a.bg-success:hover {\n background-color: #1e7e34 !important;\n}\n\n.bg-info {\n background-color: #17a2b8 !important;\n}\n\na.bg-info:focus, a.bg-info:hover {\n background-color: #117a8b !important;\n}\n\n.bg-warning {\n background-color: #ffc107 !important;\n}\n\na.bg-warning:focus, a.bg-warning:hover {\n background-color: #d39e00 !important;\n}\n\n.bg-danger {\n background-color: #dc3545 !important;\n}\n\na.bg-danger:focus, a.bg-danger:hover {\n background-color: #bd2130 !important;\n}\n\n.bg-light {\n background-color: #f8f9fa !important;\n}\n\na.bg-light:focus, a.bg-light:hover {\n background-color: #dae0e5 !important;\n}\n\n.bg-dark {\n background-color: #343a40 !important;\n}\n\na.bg-dark:focus, a.bg-dark:hover {\n background-color: #1d2124 !important;\n}\n\n.bg-transparent {\n background-color: transparent !important;\n}\n\n.border {\n border: 1px solid #e9ecef !important;\n}\n\n.border-0 {\n border: 0 !important;\n}\n\n.border-top-0 {\n border-top: 0 !important;\n}\n\n.border-right-0 {\n border-right: 0 !important;\n}\n\n.border-bottom-0 {\n border-bottom: 0 !important;\n}\n\n.border-left-0 {\n border-left: 0 !important;\n}\n\n.border-primary {\n border-color: #007bff !important;\n}\n\n.border-secondary {\n border-color: #868e96 !important;\n}\n\n.border-success {\n border-color: #28a745 !important;\n}\n\n.border-info {\n border-color: #17a2b8 !important;\n}\n\n.border-warning {\n border-color: #ffc107 !important;\n}\n\n.border-danger {\n border-color: #dc3545 !important;\n}\n\n.border-light {\n border-color: #f8f9fa !important;\n}\n\n.border-dark {\n border-color: #343a40 !important;\n}\n\n.rounded {\n border-radius: 0.25rem !important;\n}\n\n.rounded-top {\n border-top-left-radius: 0.25rem !important;\n border-top-right-radius: 0.25rem !important;\n}\n\n.rounded-right {\n border-top-right-radius: 0.25rem !important;\n border-bottom-right-radius: 0.25rem !important;\n}\n\n.rounded-bottom {\n border-bottom-right-radius: 0.25rem !important;\n border-bottom-left-radius: 0.25rem !important;\n}\n\n.rounded-left {\n border-top-left-radius: 0.25rem !important;\n border-bottom-left-radius: 0.25rem !important;\n}\n\n.rounded-circle {\n border-radius: 50%;\n}\n\n.rounded-0 {\n border-radius: 0;\n}\n\n.clearfix::after {\n display: block;\n clear: both;\n content: \"\";\n}\n\n.d-none {\n display: none !important;\n}\n\n.d-inline {\n display: inline !important;\n}\n\n.d-inline-block {\n display: inline-block !important;\n}\n\n.d-block {\n display: block !important;\n}\n\n.d-table {\n display: table !important;\n}\n\n.d-table-cell {\n display: table-cell !important;\n}\n\n.d-flex {\n display: flex !important;\n}\n\n.d-inline-flex {\n display: inline-flex !important;\n}\n\n@media (min-width: 576px) {\n .d-sm-none {\n display: none !important;\n }\n .d-sm-inline {\n display: inline !important;\n }\n .d-sm-inline-block {\n display: inline-block !important;\n }\n .d-sm-block {\n display: block !important;\n }\n .d-sm-table {\n display: table !important;\n }\n .d-sm-table-cell {\n display: table-cell !important;\n }\n .d-sm-flex {\n display: flex !important;\n }\n .d-sm-inline-flex {\n display: inline-flex !important;\n }\n}\n\n@media (min-width: 768px) {\n .d-md-none {\n display: none !important;\n }\n .d-md-inline {\n display: inline !important;\n }\n .d-md-inline-block {\n display: inline-block !important;\n }\n .d-md-block {\n display: block !important;\n }\n .d-md-table {\n display: table !important;\n }\n .d-md-table-cell {\n display: table-cell !important;\n }\n .d-md-flex {\n display: flex !important;\n }\n .d-md-inline-flex {\n display: inline-flex !important;\n }\n}\n\n@media (min-width: 992px) {\n .d-lg-none {\n display: none !important;\n }\n .d-lg-inline {\n display: inline !important;\n }\n .d-lg-inline-block {\n display: inline-block !important;\n }\n .d-lg-block {\n display: block !important;\n }\n .d-lg-table {\n display: table !important;\n }\n .d-lg-table-cell {\n display: table-cell !important;\n }\n .d-lg-flex {\n display: flex !important;\n }\n .d-lg-inline-flex {\n display: inline-flex !important;\n }\n}\n\n@media (min-width: 1200px) {\n .d-xl-none {\n display: none !important;\n }\n .d-xl-inline {\n display: inline !important;\n }\n .d-xl-inline-block {\n display: inline-block !important;\n }\n .d-xl-block {\n display: block !important;\n }\n .d-xl-table {\n display: table !important;\n }\n .d-xl-table-cell {\n display: table-cell !important;\n }\n .d-xl-flex {\n display: flex !important;\n }\n .d-xl-inline-flex {\n display: inline-flex !important;\n }\n}\n\n.d-print-block {\n display: none !important;\n}\n\n@media print {\n .d-print-block {\n display: block !important;\n }\n}\n\n.d-print-inline {\n display: none !important;\n}\n\n@media print {\n .d-print-inline {\n display: inline !important;\n }\n}\n\n.d-print-inline-block {\n display: none !important;\n}\n\n@media print {\n .d-print-inline-block {\n display: inline-block !important;\n }\n}\n\n@media print {\n .d-print-none {\n display: none !important;\n }\n}\n\n.embed-responsive {\n position: relative;\n display: block;\n width: 100%;\n padding: 0;\n overflow: hidden;\n}\n\n.embed-responsive::before {\n display: block;\n content: \"\";\n}\n\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 100%;\n height: 100%;\n border: 0;\n}\n\n.embed-responsive-21by9::before {\n padding-top: 42.857143%;\n}\n\n.embed-responsive-16by9::before {\n padding-top: 56.25%;\n}\n\n.embed-responsive-4by3::before {\n padding-top: 75%;\n}\n\n.embed-responsive-1by1::before {\n padding-top: 100%;\n}\n\n.flex-row {\n flex-direction: row !important;\n}\n\n.flex-column {\n flex-direction: column !important;\n}\n\n.flex-row-reverse {\n flex-direction: row-reverse !important;\n}\n\n.flex-column-reverse {\n flex-direction: column-reverse !important;\n}\n\n.flex-wrap {\n flex-wrap: wrap !important;\n}\n\n.flex-nowrap {\n flex-wrap: nowrap !important;\n}\n\n.flex-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n}\n\n.justify-content-start {\n justify-content: flex-start !important;\n}\n\n.justify-content-end {\n justify-content: flex-end !important;\n}\n\n.justify-content-center {\n justify-content: center !important;\n}\n\n.justify-content-between {\n justify-content: space-between !important;\n}\n\n.justify-content-around {\n justify-content: space-around !important;\n}\n\n.align-items-start {\n align-items: flex-start !important;\n}\n\n.align-items-end {\n align-items: flex-end !important;\n}\n\n.align-items-center {\n align-items: center !important;\n}\n\n.align-items-baseline {\n align-items: baseline !important;\n}\n\n.align-items-stretch {\n align-items: stretch !important;\n}\n\n.align-content-start {\n align-content: flex-start !important;\n}\n\n.align-content-end {\n align-content: flex-end !important;\n}\n\n.align-content-center {\n align-content: center !important;\n}\n\n.align-content-between {\n align-content: space-between !important;\n}\n\n.align-content-around {\n align-content: space-around !important;\n}\n\n.align-content-stretch {\n align-content: stretch !important;\n}\n\n.align-self-auto {\n align-self: auto !important;\n}\n\n.align-self-start {\n align-self: flex-start !important;\n}\n\n.align-self-end {\n align-self: flex-end !important;\n}\n\n.align-self-center {\n align-self: center !important;\n}\n\n.align-self-baseline {\n align-self: baseline !important;\n}\n\n.align-self-stretch {\n align-self: stretch !important;\n}\n\n@media (min-width: 576px) {\n .flex-sm-row {\n flex-direction: row !important;\n }\n .flex-sm-column {\n flex-direction: column !important;\n }\n .flex-sm-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-sm-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-sm-wrap {\n flex-wrap: wrap !important;\n }\n .flex-sm-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-sm-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-sm-start {\n justify-content: flex-start !important;\n }\n .justify-content-sm-end {\n justify-content: flex-end !important;\n }\n .justify-content-sm-center {\n justify-content: center !important;\n }\n .justify-content-sm-between {\n justify-content: space-between !important;\n }\n .justify-content-sm-around {\n justify-content: space-around !important;\n }\n .align-items-sm-start {\n align-items: flex-start !important;\n }\n .align-items-sm-end {\n align-items: flex-end !important;\n }\n .align-items-sm-center {\n align-items: center !important;\n }\n .align-items-sm-baseline {\n align-items: baseline !important;\n }\n .align-items-sm-stretch {\n align-items: stretch !important;\n }\n .align-content-sm-start {\n align-content: flex-start !important;\n }\n .align-content-sm-end {\n align-content: flex-end !important;\n }\n .align-content-sm-center {\n align-content: center !important;\n }\n .align-content-sm-between {\n align-content: space-between !important;\n }\n .align-content-sm-around {\n align-content: space-around !important;\n }\n .align-content-sm-stretch {\n align-content: stretch !important;\n }\n .align-self-sm-auto {\n align-self: auto !important;\n }\n .align-self-sm-start {\n align-self: flex-start !important;\n }\n .align-self-sm-end {\n align-self: flex-end !important;\n }\n .align-self-sm-center {\n align-self: center !important;\n }\n .align-self-sm-baseline {\n align-self: baseline !important;\n }\n .align-self-sm-stretch {\n align-self: stretch !important;\n }\n}\n\n@media (min-width: 768px) {\n .flex-md-row {\n flex-direction: row !important;\n }\n .flex-md-column {\n flex-direction: column !important;\n }\n .flex-md-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-md-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-md-wrap {\n flex-wrap: wrap !important;\n }\n .flex-md-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-md-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-md-start {\n justify-content: flex-start !important;\n }\n .justify-content-md-end {\n justify-content: flex-end !important;\n }\n .justify-content-md-center {\n justify-content: center !important;\n }\n .justify-content-md-between {\n justify-content: space-between !important;\n }\n .justify-content-md-around {\n justify-content: space-around !important;\n }\n .align-items-md-start {\n align-items: flex-start !important;\n }\n .align-items-md-end {\n align-items: flex-end !important;\n }\n .align-items-md-center {\n align-items: center !important;\n }\n .align-items-md-baseline {\n align-items: baseline !important;\n }\n .align-items-md-stretch {\n align-items: stretch !important;\n }\n .align-content-md-start {\n align-content: flex-start !important;\n }\n .align-content-md-end {\n align-content: flex-end !important;\n }\n .align-content-md-center {\n align-content: center !important;\n }\n .align-content-md-between {\n align-content: space-between !important;\n }\n .align-content-md-around {\n align-content: space-around !important;\n }\n .align-content-md-stretch {\n align-content: stretch !important;\n }\n .align-self-md-auto {\n align-self: auto !important;\n }\n .align-self-md-start {\n align-self: flex-start !important;\n }\n .align-self-md-end {\n align-self: flex-end !important;\n }\n .align-self-md-center {\n align-self: center !important;\n }\n .align-self-md-baseline {\n align-self: baseline !important;\n }\n .align-self-md-stretch {\n align-self: stretch !important;\n }\n}\n\n@media (min-width: 992px) {\n .flex-lg-row {\n flex-direction: row !important;\n }\n .flex-lg-column {\n flex-direction: column !important;\n }\n .flex-lg-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-lg-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-lg-wrap {\n flex-wrap: wrap !important;\n }\n .flex-lg-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-lg-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-lg-start {\n justify-content: flex-start !important;\n }\n .justify-content-lg-end {\n justify-content: flex-end !important;\n }\n .justify-content-lg-center {\n justify-content: center !important;\n }\n .justify-content-lg-between {\n justify-content: space-between !important;\n }\n .justify-content-lg-around {\n justify-content: space-around !important;\n }\n .align-items-lg-start {\n align-items: flex-start !important;\n }\n .align-items-lg-end {\n align-items: flex-end !important;\n }\n .align-items-lg-center {\n align-items: center !important;\n }\n .align-items-lg-baseline {\n align-items: baseline !important;\n }\n .align-items-lg-stretch {\n align-items: stretch !important;\n }\n .align-content-lg-start {\n align-content: flex-start !important;\n }\n .align-content-lg-end {\n align-content: flex-end !important;\n }\n .align-content-lg-center {\n align-content: center !important;\n }\n .align-content-lg-between {\n align-content: space-between !important;\n }\n .align-content-lg-around {\n align-content: space-around !important;\n }\n .align-content-lg-stretch {\n align-content: stretch !important;\n }\n .align-self-lg-auto {\n align-self: auto !important;\n }\n .align-self-lg-start {\n align-self: flex-start !important;\n }\n .align-self-lg-end {\n align-self: flex-end !important;\n }\n .align-self-lg-center {\n align-self: center !important;\n }\n .align-self-lg-baseline {\n align-self: baseline !important;\n }\n .align-self-lg-stretch {\n align-self: stretch !important;\n }\n}\n\n@media (min-width: 1200px) {\n .flex-xl-row {\n flex-direction: row !important;\n }\n .flex-xl-column {\n flex-direction: column !important;\n }\n .flex-xl-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-xl-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-xl-wrap {\n flex-wrap: wrap !important;\n }\n .flex-xl-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-xl-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-xl-start {\n justify-content: flex-start !important;\n }\n .justify-content-xl-end {\n justify-content: flex-end !important;\n }\n .justify-content-xl-center {\n justify-content: center !important;\n }\n .justify-content-xl-between {\n justify-content: space-between !important;\n }\n .justify-content-xl-around {\n justify-content: space-around !important;\n }\n .align-items-xl-start {\n align-items: flex-start !important;\n }\n .align-items-xl-end {\n align-items: flex-end !important;\n }\n .align-items-xl-center {\n align-items: center !important;\n }\n .align-items-xl-baseline {\n align-items: baseline !important;\n }\n .align-items-xl-stretch {\n align-items: stretch !important;\n }\n .align-content-xl-start {\n align-content: flex-start !important;\n }\n .align-content-xl-end {\n align-content: flex-end !important;\n }\n .align-content-xl-center {\n align-content: center !important;\n }\n .align-content-xl-between {\n align-content: space-between !important;\n }\n .align-content-xl-around {\n align-content: space-around !important;\n }\n .align-content-xl-stretch {\n align-content: stretch !important;\n }\n .align-self-xl-auto {\n align-self: auto !important;\n }\n .align-self-xl-start {\n align-self: flex-start !important;\n }\n .align-self-xl-end {\n align-self: flex-end !important;\n }\n .align-self-xl-center {\n align-self: center !important;\n }\n .align-self-xl-baseline {\n align-self: baseline !important;\n }\n .align-self-xl-stretch {\n align-self: stretch !important;\n }\n}\n\n.float-left {\n float: left !important;\n}\n\n.float-right {\n float: right !important;\n}\n\n.float-none {\n float: none !important;\n}\n\n@media (min-width: 576px) {\n .float-sm-left {\n float: left !important;\n }\n .float-sm-right {\n float: right !important;\n }\n .float-sm-none {\n float: none !important;\n }\n}\n\n@media (min-width: 768px) {\n .float-md-left {\n float: left !important;\n }\n .float-md-right {\n float: right !important;\n }\n .float-md-none {\n float: none !important;\n }\n}\n\n@media (min-width: 992px) {\n .float-lg-left {\n float: left !important;\n }\n .float-lg-right {\n float: right !important;\n }\n .float-lg-none {\n float: none !important;\n }\n}\n\n@media (min-width: 1200px) {\n .float-xl-left {\n float: left !important;\n }\n .float-xl-right {\n float: right !important;\n }\n .float-xl-none {\n float: none !important;\n }\n}\n\n.fixed-top {\n position: fixed;\n top: 0;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n\n.fixed-bottom {\n position: fixed;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1030;\n}\n\n@supports (position: sticky) {\n .sticky-top {\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n}\n\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n clip-path: inset(50%);\n border: 0;\n}\n\n.sr-only-focusable:active, .sr-only-focusable:focus {\n position: static;\n width: auto;\n height: auto;\n overflow: visible;\n clip: auto;\n white-space: normal;\n clip-path: none;\n}\n\n.w-25 {\n width: 25% !important;\n}\n\n.w-50 {\n width: 50% !important;\n}\n\n.w-75 {\n width: 75% !important;\n}\n\n.w-100 {\n width: 100% !important;\n}\n\n.h-25 {\n height: 25% !important;\n}\n\n.h-50 {\n height: 50% !important;\n}\n\n.h-75 {\n height: 75% !important;\n}\n\n.h-100 {\n height: 100% !important;\n}\n\n.mw-100 {\n max-width: 100% !important;\n}\n\n.mh-100 {\n max-height: 100% !important;\n}\n\n.m-0 {\n margin: 0 !important;\n}\n\n.mt-0 {\n margin-top: 0 !important;\n}\n\n.mr-0 {\n margin-right: 0 !important;\n}\n\n.mb-0 {\n margin-bottom: 0 !important;\n}\n\n.ml-0 {\n margin-left: 0 !important;\n}\n\n.mx-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n}\n\n.my-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n.m-1 {\n margin: 0.25rem !important;\n}\n\n.mt-1 {\n margin-top: 0.25rem !important;\n}\n\n.mr-1 {\n margin-right: 0.25rem !important;\n}\n\n.mb-1 {\n margin-bottom: 0.25rem !important;\n}\n\n.ml-1 {\n margin-left: 0.25rem !important;\n}\n\n.mx-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n}\n\n.my-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n}\n\n.m-2 {\n margin: 0.5rem !important;\n}\n\n.mt-2 {\n margin-top: 0.5rem !important;\n}\n\n.mr-2 {\n margin-right: 0.5rem !important;\n}\n\n.mb-2 {\n margin-bottom: 0.5rem !important;\n}\n\n.ml-2 {\n margin-left: 0.5rem !important;\n}\n\n.mx-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n}\n\n.my-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n}\n\n.m-3 {\n margin: 1rem !important;\n}\n\n.mt-3 {\n margin-top: 1rem !important;\n}\n\n.mr-3 {\n margin-right: 1rem !important;\n}\n\n.mb-3 {\n margin-bottom: 1rem !important;\n}\n\n.ml-3 {\n margin-left: 1rem !important;\n}\n\n.mx-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n}\n\n.my-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n}\n\n.m-4 {\n margin: 1.5rem !important;\n}\n\n.mt-4 {\n margin-top: 1.5rem !important;\n}\n\n.mr-4 {\n margin-right: 1.5rem !important;\n}\n\n.mb-4 {\n margin-bottom: 1.5rem !important;\n}\n\n.ml-4 {\n margin-left: 1.5rem !important;\n}\n\n.mx-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n}\n\n.my-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n}\n\n.m-5 {\n margin: 3rem !important;\n}\n\n.mt-5 {\n margin-top: 3rem !important;\n}\n\n.mr-5 {\n margin-right: 3rem !important;\n}\n\n.mb-5 {\n margin-bottom: 3rem !important;\n}\n\n.ml-5 {\n margin-left: 3rem !important;\n}\n\n.mx-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n}\n\n.my-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n}\n\n.p-0 {\n padding: 0 !important;\n}\n\n.pt-0 {\n padding-top: 0 !important;\n}\n\n.pr-0 {\n padding-right: 0 !important;\n}\n\n.pb-0 {\n padding-bottom: 0 !important;\n}\n\n.pl-0 {\n padding-left: 0 !important;\n}\n\n.px-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n}\n\n.py-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n}\n\n.p-1 {\n padding: 0.25rem !important;\n}\n\n.pt-1 {\n padding-top: 0.25rem !important;\n}\n\n.pr-1 {\n padding-right: 0.25rem !important;\n}\n\n.pb-1 {\n padding-bottom: 0.25rem !important;\n}\n\n.pl-1 {\n padding-left: 0.25rem !important;\n}\n\n.px-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n}\n\n.py-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n}\n\n.p-2 {\n padding: 0.5rem !important;\n}\n\n.pt-2 {\n padding-top: 0.5rem !important;\n}\n\n.pr-2 {\n padding-right: 0.5rem !important;\n}\n\n.pb-2 {\n padding-bottom: 0.5rem !important;\n}\n\n.pl-2 {\n padding-left: 0.5rem !important;\n}\n\n.px-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n}\n\n.py-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n}\n\n.p-3 {\n padding: 1rem !important;\n}\n\n.pt-3 {\n padding-top: 1rem !important;\n}\n\n.pr-3 {\n padding-right: 1rem !important;\n}\n\n.pb-3 {\n padding-bottom: 1rem !important;\n}\n\n.pl-3 {\n padding-left: 1rem !important;\n}\n\n.px-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n}\n\n.py-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n}\n\n.p-4 {\n padding: 1.5rem !important;\n}\n\n.pt-4 {\n padding-top: 1.5rem !important;\n}\n\n.pr-4 {\n padding-right: 1.5rem !important;\n}\n\n.pb-4 {\n padding-bottom: 1.5rem !important;\n}\n\n.pl-4 {\n padding-left: 1.5rem !important;\n}\n\n.px-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n}\n\n.py-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n}\n\n.p-5 {\n padding: 3rem !important;\n}\n\n.pt-5 {\n padding-top: 3rem !important;\n}\n\n.pr-5 {\n padding-right: 3rem !important;\n}\n\n.pb-5 {\n padding-bottom: 3rem !important;\n}\n\n.pl-5 {\n padding-left: 3rem !important;\n}\n\n.px-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n}\n\n.py-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n}\n\n.m-auto {\n margin: auto !important;\n}\n\n.mt-auto {\n margin-top: auto !important;\n}\n\n.mr-auto {\n margin-right: auto !important;\n}\n\n.mb-auto {\n margin-bottom: auto !important;\n}\n\n.ml-auto {\n margin-left: auto !important;\n}\n\n.mx-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n}\n\n.my-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n}\n\n@media (min-width: 576px) {\n .m-sm-0 {\n margin: 0 !important;\n }\n .mt-sm-0 {\n margin-top: 0 !important;\n }\n .mr-sm-0 {\n margin-right: 0 !important;\n }\n .mb-sm-0 {\n margin-bottom: 0 !important;\n }\n .ml-sm-0 {\n margin-left: 0 !important;\n }\n .mx-sm-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .my-sm-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .m-sm-1 {\n margin: 0.25rem !important;\n }\n .mt-sm-1 {\n margin-top: 0.25rem !important;\n }\n .mr-sm-1 {\n margin-right: 0.25rem !important;\n }\n .mb-sm-1 {\n margin-bottom: 0.25rem !important;\n }\n .ml-sm-1 {\n margin-left: 0.25rem !important;\n }\n .mx-sm-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .my-sm-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .m-sm-2 {\n margin: 0.5rem !important;\n }\n .mt-sm-2 {\n margin-top: 0.5rem !important;\n }\n .mr-sm-2 {\n margin-right: 0.5rem !important;\n }\n .mb-sm-2 {\n margin-bottom: 0.5rem !important;\n }\n .ml-sm-2 {\n margin-left: 0.5rem !important;\n }\n .mx-sm-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .my-sm-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .m-sm-3 {\n margin: 1rem !important;\n }\n .mt-sm-3 {\n margin-top: 1rem !important;\n }\n .mr-sm-3 {\n margin-right: 1rem !important;\n }\n .mb-sm-3 {\n margin-bottom: 1rem !important;\n }\n .ml-sm-3 {\n margin-left: 1rem !important;\n }\n .mx-sm-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .my-sm-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .m-sm-4 {\n margin: 1.5rem !important;\n }\n .mt-sm-4 {\n margin-top: 1.5rem !important;\n }\n .mr-sm-4 {\n margin-right: 1.5rem !important;\n }\n .mb-sm-4 {\n margin-bottom: 1.5rem !important;\n }\n .ml-sm-4 {\n margin-left: 1.5rem !important;\n }\n .mx-sm-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .my-sm-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .m-sm-5 {\n margin: 3rem !important;\n }\n .mt-sm-5 {\n margin-top: 3rem !important;\n }\n .mr-sm-5 {\n margin-right: 3rem !important;\n }\n .mb-sm-5 {\n margin-bottom: 3rem !important;\n }\n .ml-sm-5 {\n margin-left: 3rem !important;\n }\n .mx-sm-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .my-sm-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .p-sm-0 {\n padding: 0 !important;\n }\n .pt-sm-0 {\n padding-top: 0 !important;\n }\n .pr-sm-0 {\n padding-right: 0 !important;\n }\n .pb-sm-0 {\n padding-bottom: 0 !important;\n }\n .pl-sm-0 {\n padding-left: 0 !important;\n }\n .px-sm-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .py-sm-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .p-sm-1 {\n padding: 0.25rem !important;\n }\n .pt-sm-1 {\n padding-top: 0.25rem !important;\n }\n .pr-sm-1 {\n padding-right: 0.25rem !important;\n }\n .pb-sm-1 {\n padding-bottom: 0.25rem !important;\n }\n .pl-sm-1 {\n padding-left: 0.25rem !important;\n }\n .px-sm-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .py-sm-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .p-sm-2 {\n padding: 0.5rem !important;\n }\n .pt-sm-2 {\n padding-top: 0.5rem !important;\n }\n .pr-sm-2 {\n padding-right: 0.5rem !important;\n }\n .pb-sm-2 {\n padding-bottom: 0.5rem !important;\n }\n .pl-sm-2 {\n padding-left: 0.5rem !important;\n }\n .px-sm-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .py-sm-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .p-sm-3 {\n padding: 1rem !important;\n }\n .pt-sm-3 {\n padding-top: 1rem !important;\n }\n .pr-sm-3 {\n padding-right: 1rem !important;\n }\n .pb-sm-3 {\n padding-bottom: 1rem !important;\n }\n .pl-sm-3 {\n padding-left: 1rem !important;\n }\n .px-sm-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .py-sm-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .p-sm-4 {\n padding: 1.5rem !important;\n }\n .pt-sm-4 {\n padding-top: 1.5rem !important;\n }\n .pr-sm-4 {\n padding-right: 1.5rem !important;\n }\n .pb-sm-4 {\n padding-bottom: 1.5rem !important;\n }\n .pl-sm-4 {\n padding-left: 1.5rem !important;\n }\n .px-sm-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .py-sm-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .p-sm-5 {\n padding: 3rem !important;\n }\n .pt-sm-5 {\n padding-top: 3rem !important;\n }\n .pr-sm-5 {\n padding-right: 3rem !important;\n }\n .pb-sm-5 {\n padding-bottom: 3rem !important;\n }\n .pl-sm-5 {\n padding-left: 3rem !important;\n }\n .px-sm-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-sm-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .m-sm-auto {\n margin: auto !important;\n }\n .mt-sm-auto {\n margin-top: auto !important;\n }\n .mr-sm-auto {\n margin-right: auto !important;\n }\n .mb-sm-auto {\n margin-bottom: auto !important;\n }\n .ml-sm-auto {\n margin-left: auto !important;\n }\n .mx-sm-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-sm-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n}\n\n@media (min-width: 768px) {\n .m-md-0 {\n margin: 0 !important;\n }\n .mt-md-0 {\n margin-top: 0 !important;\n }\n .mr-md-0 {\n margin-right: 0 !important;\n }\n .mb-md-0 {\n margin-bottom: 0 !important;\n }\n .ml-md-0 {\n margin-left: 0 !important;\n }\n .mx-md-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .my-md-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .m-md-1 {\n margin: 0.25rem !important;\n }\n .mt-md-1 {\n margin-top: 0.25rem !important;\n }\n .mr-md-1 {\n margin-right: 0.25rem !important;\n }\n .mb-md-1 {\n margin-bottom: 0.25rem !important;\n }\n .ml-md-1 {\n margin-left: 0.25rem !important;\n }\n .mx-md-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .my-md-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .m-md-2 {\n margin: 0.5rem !important;\n }\n .mt-md-2 {\n margin-top: 0.5rem !important;\n }\n .mr-md-2 {\n margin-right: 0.5rem !important;\n }\n .mb-md-2 {\n margin-bottom: 0.5rem !important;\n }\n .ml-md-2 {\n margin-left: 0.5rem !important;\n }\n .mx-md-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .my-md-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .m-md-3 {\n margin: 1rem !important;\n }\n .mt-md-3 {\n margin-top: 1rem !important;\n }\n .mr-md-3 {\n margin-right: 1rem !important;\n }\n .mb-md-3 {\n margin-bottom: 1rem !important;\n }\n .ml-md-3 {\n margin-left: 1rem !important;\n }\n .mx-md-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .my-md-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .m-md-4 {\n margin: 1.5rem !important;\n }\n .mt-md-4 {\n margin-top: 1.5rem !important;\n }\n .mr-md-4 {\n margin-right: 1.5rem !important;\n }\n .mb-md-4 {\n margin-bottom: 1.5rem !important;\n }\n .ml-md-4 {\n margin-left: 1.5rem !important;\n }\n .mx-md-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .my-md-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .m-md-5 {\n margin: 3rem !important;\n }\n .mt-md-5 {\n margin-top: 3rem !important;\n }\n .mr-md-5 {\n margin-right: 3rem !important;\n }\n .mb-md-5 {\n margin-bottom: 3rem !important;\n }\n .ml-md-5 {\n margin-left: 3rem !important;\n }\n .mx-md-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .my-md-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .p-md-0 {\n padding: 0 !important;\n }\n .pt-md-0 {\n padding-top: 0 !important;\n }\n .pr-md-0 {\n padding-right: 0 !important;\n }\n .pb-md-0 {\n padding-bottom: 0 !important;\n }\n .pl-md-0 {\n padding-left: 0 !important;\n }\n .px-md-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .py-md-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .p-md-1 {\n padding: 0.25rem !important;\n }\n .pt-md-1 {\n padding-top: 0.25rem !important;\n }\n .pr-md-1 {\n padding-right: 0.25rem !important;\n }\n .pb-md-1 {\n padding-bottom: 0.25rem !important;\n }\n .pl-md-1 {\n padding-left: 0.25rem !important;\n }\n .px-md-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .py-md-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .p-md-2 {\n padding: 0.5rem !important;\n }\n .pt-md-2 {\n padding-top: 0.5rem !important;\n }\n .pr-md-2 {\n padding-right: 0.5rem !important;\n }\n .pb-md-2 {\n padding-bottom: 0.5rem !important;\n }\n .pl-md-2 {\n padding-left: 0.5rem !important;\n }\n .px-md-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .py-md-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .p-md-3 {\n padding: 1rem !important;\n }\n .pt-md-3 {\n padding-top: 1rem !important;\n }\n .pr-md-3 {\n padding-right: 1rem !important;\n }\n .pb-md-3 {\n padding-bottom: 1rem !important;\n }\n .pl-md-3 {\n padding-left: 1rem !important;\n }\n .px-md-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .py-md-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .p-md-4 {\n padding: 1.5rem !important;\n }\n .pt-md-4 {\n padding-top: 1.5rem !important;\n }\n .pr-md-4 {\n padding-right: 1.5rem !important;\n }\n .pb-md-4 {\n padding-bottom: 1.5rem !important;\n }\n .pl-md-4 {\n padding-left: 1.5rem !important;\n }\n .px-md-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .py-md-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .p-md-5 {\n padding: 3rem !important;\n }\n .pt-md-5 {\n padding-top: 3rem !important;\n }\n .pr-md-5 {\n padding-right: 3rem !important;\n }\n .pb-md-5 {\n padding-bottom: 3rem !important;\n }\n .pl-md-5 {\n padding-left: 3rem !important;\n }\n .px-md-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-md-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .m-md-auto {\n margin: auto !important;\n }\n .mt-md-auto {\n margin-top: auto !important;\n }\n .mr-md-auto {\n margin-right: auto !important;\n }\n .mb-md-auto {\n margin-bottom: auto !important;\n }\n .ml-md-auto {\n margin-left: auto !important;\n }\n .mx-md-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-md-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n}\n\n@media (min-width: 992px) {\n .m-lg-0 {\n margin: 0 !important;\n }\n .mt-lg-0 {\n margin-top: 0 !important;\n }\n .mr-lg-0 {\n margin-right: 0 !important;\n }\n .mb-lg-0 {\n margin-bottom: 0 !important;\n }\n .ml-lg-0 {\n margin-left: 0 !important;\n }\n .mx-lg-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .my-lg-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .m-lg-1 {\n margin: 0.25rem !important;\n }\n .mt-lg-1 {\n margin-top: 0.25rem !important;\n }\n .mr-lg-1 {\n margin-right: 0.25rem !important;\n }\n .mb-lg-1 {\n margin-bottom: 0.25rem !important;\n }\n .ml-lg-1 {\n margin-left: 0.25rem !important;\n }\n .mx-lg-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .my-lg-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .m-lg-2 {\n margin: 0.5rem !important;\n }\n .mt-lg-2 {\n margin-top: 0.5rem !important;\n }\n .mr-lg-2 {\n margin-right: 0.5rem !important;\n }\n .mb-lg-2 {\n margin-bottom: 0.5rem !important;\n }\n .ml-lg-2 {\n margin-left: 0.5rem !important;\n }\n .mx-lg-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .my-lg-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .m-lg-3 {\n margin: 1rem !important;\n }\n .mt-lg-3 {\n margin-top: 1rem !important;\n }\n .mr-lg-3 {\n margin-right: 1rem !important;\n }\n .mb-lg-3 {\n margin-bottom: 1rem !important;\n }\n .ml-lg-3 {\n margin-left: 1rem !important;\n }\n .mx-lg-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .my-lg-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .m-lg-4 {\n margin: 1.5rem !important;\n }\n .mt-lg-4 {\n margin-top: 1.5rem !important;\n }\n .mr-lg-4 {\n margin-right: 1.5rem !important;\n }\n .mb-lg-4 {\n margin-bottom: 1.5rem !important;\n }\n .ml-lg-4 {\n margin-left: 1.5rem !important;\n }\n .mx-lg-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .my-lg-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .m-lg-5 {\n margin: 3rem !important;\n }\n .mt-lg-5 {\n margin-top: 3rem !important;\n }\n .mr-lg-5 {\n margin-right: 3rem !important;\n }\n .mb-lg-5 {\n margin-bottom: 3rem !important;\n }\n .ml-lg-5 {\n margin-left: 3rem !important;\n }\n .mx-lg-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .my-lg-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .p-lg-0 {\n padding: 0 !important;\n }\n .pt-lg-0 {\n padding-top: 0 !important;\n }\n .pr-lg-0 {\n padding-right: 0 !important;\n }\n .pb-lg-0 {\n padding-bottom: 0 !important;\n }\n .pl-lg-0 {\n padding-left: 0 !important;\n }\n .px-lg-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .py-lg-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .p-lg-1 {\n padding: 0.25rem !important;\n }\n .pt-lg-1 {\n padding-top: 0.25rem !important;\n }\n .pr-lg-1 {\n padding-right: 0.25rem !important;\n }\n .pb-lg-1 {\n padding-bottom: 0.25rem !important;\n }\n .pl-lg-1 {\n padding-left: 0.25rem !important;\n }\n .px-lg-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .py-lg-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .p-lg-2 {\n padding: 0.5rem !important;\n }\n .pt-lg-2 {\n padding-top: 0.5rem !important;\n }\n .pr-lg-2 {\n padding-right: 0.5rem !important;\n }\n .pb-lg-2 {\n padding-bottom: 0.5rem !important;\n }\n .pl-lg-2 {\n padding-left: 0.5rem !important;\n }\n .px-lg-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .py-lg-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .p-lg-3 {\n padding: 1rem !important;\n }\n .pt-lg-3 {\n padding-top: 1rem !important;\n }\n .pr-lg-3 {\n padding-right: 1rem !important;\n }\n .pb-lg-3 {\n padding-bottom: 1rem !important;\n }\n .pl-lg-3 {\n padding-left: 1rem !important;\n }\n .px-lg-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .py-lg-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .p-lg-4 {\n padding: 1.5rem !important;\n }\n .pt-lg-4 {\n padding-top: 1.5rem !important;\n }\n .pr-lg-4 {\n padding-right: 1.5rem !important;\n }\n .pb-lg-4 {\n padding-bottom: 1.5rem !important;\n }\n .pl-lg-4 {\n padding-left: 1.5rem !important;\n }\n .px-lg-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .py-lg-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .p-lg-5 {\n padding: 3rem !important;\n }\n .pt-lg-5 {\n padding-top: 3rem !important;\n }\n .pr-lg-5 {\n padding-right: 3rem !important;\n }\n .pb-lg-5 {\n padding-bottom: 3rem !important;\n }\n .pl-lg-5 {\n padding-left: 3rem !important;\n }\n .px-lg-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-lg-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .m-lg-auto {\n margin: auto !important;\n }\n .mt-lg-auto {\n margin-top: auto !important;\n }\n .mr-lg-auto {\n margin-right: auto !important;\n }\n .mb-lg-auto {\n margin-bottom: auto !important;\n }\n .ml-lg-auto {\n margin-left: auto !important;\n }\n .mx-lg-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-lg-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n}\n\n@media (min-width: 1200px) {\n .m-xl-0 {\n margin: 0 !important;\n }\n .mt-xl-0 {\n margin-top: 0 !important;\n }\n .mr-xl-0 {\n margin-right: 0 !important;\n }\n .mb-xl-0 {\n margin-bottom: 0 !important;\n }\n .ml-xl-0 {\n margin-left: 0 !important;\n }\n .mx-xl-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .my-xl-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .m-xl-1 {\n margin: 0.25rem !important;\n }\n .mt-xl-1 {\n margin-top: 0.25rem !important;\n }\n .mr-xl-1 {\n margin-right: 0.25rem !important;\n }\n .mb-xl-1 {\n margin-bottom: 0.25rem !important;\n }\n .ml-xl-1 {\n margin-left: 0.25rem !important;\n }\n .mx-xl-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .my-xl-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .m-xl-2 {\n margin: 0.5rem !important;\n }\n .mt-xl-2 {\n margin-top: 0.5rem !important;\n }\n .mr-xl-2 {\n margin-right: 0.5rem !important;\n }\n .mb-xl-2 {\n margin-bottom: 0.5rem !important;\n }\n .ml-xl-2 {\n margin-left: 0.5rem !important;\n }\n .mx-xl-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .my-xl-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .m-xl-3 {\n margin: 1rem !important;\n }\n .mt-xl-3 {\n margin-top: 1rem !important;\n }\n .mr-xl-3 {\n margin-right: 1rem !important;\n }\n .mb-xl-3 {\n margin-bottom: 1rem !important;\n }\n .ml-xl-3 {\n margin-left: 1rem !important;\n }\n .mx-xl-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .my-xl-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .m-xl-4 {\n margin: 1.5rem !important;\n }\n .mt-xl-4 {\n margin-top: 1.5rem !important;\n }\n .mr-xl-4 {\n margin-right: 1.5rem !important;\n }\n .mb-xl-4 {\n margin-bottom: 1.5rem !important;\n }\n .ml-xl-4 {\n margin-left: 1.5rem !important;\n }\n .mx-xl-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .my-xl-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .m-xl-5 {\n margin: 3rem !important;\n }\n .mt-xl-5 {\n margin-top: 3rem !important;\n }\n .mr-xl-5 {\n margin-right: 3rem !important;\n }\n .mb-xl-5 {\n margin-bottom: 3rem !important;\n }\n .ml-xl-5 {\n margin-left: 3rem !important;\n }\n .mx-xl-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .my-xl-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .p-xl-0 {\n padding: 0 !important;\n }\n .pt-xl-0 {\n padding-top: 0 !important;\n }\n .pr-xl-0 {\n padding-right: 0 !important;\n }\n .pb-xl-0 {\n padding-bottom: 0 !important;\n }\n .pl-xl-0 {\n padding-left: 0 !important;\n }\n .px-xl-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .py-xl-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .p-xl-1 {\n padding: 0.25rem !important;\n }\n .pt-xl-1 {\n padding-top: 0.25rem !important;\n }\n .pr-xl-1 {\n padding-right: 0.25rem !important;\n }\n .pb-xl-1 {\n padding-bottom: 0.25rem !important;\n }\n .pl-xl-1 {\n padding-left: 0.25rem !important;\n }\n .px-xl-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .py-xl-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .p-xl-2 {\n padding: 0.5rem !important;\n }\n .pt-xl-2 {\n padding-top: 0.5rem !important;\n }\n .pr-xl-2 {\n padding-right: 0.5rem !important;\n }\n .pb-xl-2 {\n padding-bottom: 0.5rem !important;\n }\n .pl-xl-2 {\n padding-left: 0.5rem !important;\n }\n .px-xl-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .py-xl-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .p-xl-3 {\n padding: 1rem !important;\n }\n .pt-xl-3 {\n padding-top: 1rem !important;\n }\n .pr-xl-3 {\n padding-right: 1rem !important;\n }\n .pb-xl-3 {\n padding-bottom: 1rem !important;\n }\n .pl-xl-3 {\n padding-left: 1rem !important;\n }\n .px-xl-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .py-xl-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .p-xl-4 {\n padding: 1.5rem !important;\n }\n .pt-xl-4 {\n padding-top: 1.5rem !important;\n }\n .pr-xl-4 {\n padding-right: 1.5rem !important;\n }\n .pb-xl-4 {\n padding-bottom: 1.5rem !important;\n }\n .pl-xl-4 {\n padding-left: 1.5rem !important;\n }\n .px-xl-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .py-xl-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .p-xl-5 {\n padding: 3rem !important;\n }\n .pt-xl-5 {\n padding-top: 3rem !important;\n }\n .pr-xl-5 {\n padding-right: 3rem !important;\n }\n .pb-xl-5 {\n padding-bottom: 3rem !important;\n }\n .pl-xl-5 {\n padding-left: 3rem !important;\n }\n .px-xl-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-xl-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .m-xl-auto {\n margin: auto !important;\n }\n .mt-xl-auto {\n margin-top: auto !important;\n }\n .mr-xl-auto {\n margin-right: auto !important;\n }\n .mb-xl-auto {\n margin-bottom: auto !important;\n }\n .ml-xl-auto {\n margin-left: auto !important;\n }\n .mx-xl-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-xl-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n}\n\n.text-justify {\n text-align: justify !important;\n}\n\n.text-nowrap {\n white-space: nowrap !important;\n}\n\n.text-truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.text-left {\n text-align: left !important;\n}\n\n.text-right {\n text-align: right !important;\n}\n\n.text-center {\n text-align: center !important;\n}\n\n@media (min-width: 576px) {\n .text-sm-left {\n text-align: left !important;\n }\n .text-sm-right {\n text-align: right !important;\n }\n .text-sm-center {\n text-align: center !important;\n }\n}\n\n@media (min-width: 768px) {\n .text-md-left {\n text-align: left !important;\n }\n .text-md-right {\n text-align: right !important;\n }\n .text-md-center {\n text-align: center !important;\n }\n}\n\n@media (min-width: 992px) {\n .text-lg-left {\n text-align: left !important;\n }\n .text-lg-right {\n text-align: right !important;\n }\n .text-lg-center {\n text-align: center !important;\n }\n}\n\n@media (min-width: 1200px) {\n .text-xl-left {\n text-align: left !important;\n }\n .text-xl-right {\n text-align: right !important;\n }\n .text-xl-center {\n text-align: center !important;\n }\n}\n\n.text-lowercase {\n text-transform: lowercase !important;\n}\n\n.text-uppercase {\n text-transform: uppercase !important;\n}\n\n.text-capitalize {\n text-transform: capitalize !important;\n}\n\n.font-weight-normal {\n font-weight: normal;\n}\n\n.font-weight-bold {\n font-weight: bold;\n}\n\n.font-italic {\n font-style: italic;\n}\n\n.text-white {\n color: #fff !important;\n}\n\n.text-primary {\n color: #007bff !important;\n}\n\na.text-primary:focus, a.text-primary:hover {\n color: #0062cc !important;\n}\n\n.text-secondary {\n color: #868e96 !important;\n}\n\na.text-secondary:focus, a.text-secondary:hover {\n color: #6c757d !important;\n}\n\n.text-success {\n color: #28a745 !important;\n}\n\na.text-success:focus, a.text-success:hover {\n color: #1e7e34 !important;\n}\n\n.text-info {\n color: #17a2b8 !important;\n}\n\na.text-info:focus, a.text-info:hover {\n color: #117a8b !important;\n}\n\n.text-warning {\n color: #ffc107 !important;\n}\n\na.text-warning:focus, a.text-warning:hover {\n color: #d39e00 !important;\n}\n\n.text-danger {\n color: #dc3545 !important;\n}\n\na.text-danger:focus, a.text-danger:hover {\n color: #bd2130 !important;\n}\n\n.text-light {\n color: #f8f9fa !important;\n}\n\na.text-light:focus, a.text-light:hover {\n color: #dae0e5 !important;\n}\n\n.text-dark {\n color: #343a40 !important;\n}\n\na.text-dark:focus, a.text-dark:hover {\n color: #1d2124 !important;\n}\n\n.text-muted {\n color: #ced4da !important;\n}\n\n.text-hide {\n font: 0/0 a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n\n.visible {\n visibility: visible !important;\n}\n\n.invisible {\n visibility: hidden !important;\n}\n\n/*# sourceMappingURL=bootstrap.css.map */",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]} \ No newline at end of file
diff --git a/library/bootstrap/css/bootstrap.min.css b/library/bootstrap/css/bootstrap.min.css
index 96fbfae61..23b532165 100644
--- a/library/bootstrap/css/bootstrap.min.css
+++ b/library/bootstrap/css/bootstrap.min.css
@@ -3,5 +3,5 @@
* Copyright 2011-2017 The Bootstrap Authors
* Copyright 2011-2017 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- */@media print{*,::after,::before,blockquote::first-letter,blockquote::first-line,div::first-letter,div::first-line,li::first-letter,li::first-line,p::first-letter,p::first-line{text-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}html{box-sizing:border-box;font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}*,::after,::before{box-sizing:inherit}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}[role=button],a,area,button,input,label,select,summary,textarea{-ms-touch-action:manipulation;touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#868e96;text-align:left;caption-side:bottom}th{text-align:left}label{display:inline-block;margin-bottom:.5rem}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.1}.display-2{font-size:5.5rem;font-weight:300;line-height:1.1}.display-3{font-size:4.5rem;font-weight:300;line-height:1.1}.display-4{font-size:3.5rem;font-weight:300;line-height:1.1}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:5px}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#868e96}.blockquote-footer::before{content:"\2014 \00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #ddd;border-radius:.25rem;transition:all .2s ease-in-out;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#868e96}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}code{padding:.2rem .4rem;font-size:90%;color:#bd4147;background-color:#f8f9fa;border-radius:.25rem}a>code{padding:0;color:inherit;background-color:inherit}kbd{padding:.2rem .4rem;font-size:90%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;margin-top:0;margin-bottom:1rem;font-size:90%;color:#212529}pre code{padding:0;font-size:inherit;color:inherit;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-right:15px;padding-left:15px}@media (min-width:576px){.container{width:540px;max-width:100%}}@media (min-width:768px){.container{width:720px;max-width:100%}}@media (min-width:992px){.container{width:960px;max-width:100%}}@media (min-width:1200px){.container{width:1140px;max-width:100%}}.container-fluid{width:100%;margin-right:auto;margin-left:auto;padding-right:15px;padding-left:15px}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-9{-ms-flex-order:9;order:9}.order-10{-ms-flex-order:10;order:10}.order-11{-ms-flex-order:11;order:11}.order-12{-ms-flex-order:12;order:12}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-sm-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-1{-ms-flex-order:1;order:1}.order-sm-2{-ms-flex-order:2;order:2}.order-sm-3{-ms-flex-order:3;order:3}.order-sm-4{-ms-flex-order:4;order:4}.order-sm-5{-ms-flex-order:5;order:5}.order-sm-6{-ms-flex-order:6;order:6}.order-sm-7{-ms-flex-order:7;order:7}.order-sm-8{-ms-flex-order:8;order:8}.order-sm-9{-ms-flex-order:9;order:9}.order-sm-10{-ms-flex-order:10;order:10}.order-sm-11{-ms-flex-order:11;order:11}.order-sm-12{-ms-flex-order:12;order:12}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-md-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-1{-ms-flex-order:1;order:1}.order-md-2{-ms-flex-order:2;order:2}.order-md-3{-ms-flex-order:3;order:3}.order-md-4{-ms-flex-order:4;order:4}.order-md-5{-ms-flex-order:5;order:5}.order-md-6{-ms-flex-order:6;order:6}.order-md-7{-ms-flex-order:7;order:7}.order-md-8{-ms-flex-order:8;order:8}.order-md-9{-ms-flex-order:9;order:9}.order-md-10{-ms-flex-order:10;order:10}.order-md-11{-ms-flex-order:11;order:11}.order-md-12{-ms-flex-order:12;order:12}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-lg-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-1{-ms-flex-order:1;order:1}.order-lg-2{-ms-flex-order:2;order:2}.order-lg-3{-ms-flex-order:3;order:3}.order-lg-4{-ms-flex-order:4;order:4}.order-lg-5{-ms-flex-order:5;order:5}.order-lg-6{-ms-flex-order:6;order:6}.order-lg-7{-ms-flex-order:7;order:7}.order-lg-8{-ms-flex-order:8;order:8}.order-lg-9{-ms-flex-order:9;order:9}.order-lg-10{-ms-flex-order:10;order:10}.order-lg-11{-ms-flex-order:11;order:11}.order-lg-12{-ms-flex-order:12;order:12}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-xl-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-1{-ms-flex-order:1;order:1}.order-xl-2{-ms-flex-order:2;order:2}.order-xl-3{-ms-flex-order:3;order:3}.order-xl-4{-ms-flex-order:4;order:4}.order-xl-5{-ms-flex-order:5;order:5}.order-xl-6{-ms-flex-order:6;order:6}.order-xl-7{-ms-flex-order:7;order:7}.order-xl-8{-ms-flex-order:8;order:8}.order-xl-9{-ms-flex-order:9;order:9}.order-xl-10{-ms-flex-order:10;order:10}.order-xl-11{-ms-flex-order:11;order:11}.order-xl-12{-ms-flex-order:12;order:12}}.table{width:100%;max-width:100%;margin-bottom:1rem;background-color:transparent}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #e9ecef}.table thead th{vertical-align:bottom;border-bottom:2px solid #e9ecef}.table tbody+tbody{border-top:2px solid #e9ecef}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #e9ecef}.table-bordered td,.table-bordered th{border:1px solid #e9ecef}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#dddfe2}.table-hover .table-secondary:hover{background-color:#cfd2d6}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#cfd2d6}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.thead-inverse th{color:#fff;background-color:#212529}.thead-default th{color:#495057;background-color:#e9ecef}.table-inverse{color:#fff;background-color:#212529}.table-inverse td,.table-inverse th,.table-inverse thead th{border-color:#32383e}.table-inverse.table-bordered{border:0}.table-inverse.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-inverse.table-hover tbody tr:hover{background-color:rgba(255,255,255,.075)}@media (max-width:991px){.table-responsive{display:block;width:100%;overflow-x:auto;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive.table-bordered{border:0}}.form-control{display:block;width:100%;padding:.5rem .75rem;font-size:1rem;line-height:1.25;color:#495057;background-color:#fff;background-image:none;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0}.form-control::-webkit-input-placeholder{color:#868e96;opacity:1}.form-control:-ms-input-placeholder{color:#868e96;opacity:1}.form-control::placeholder{color:#868e96;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:not([size]):not([multiple]){height:calc(2.25rem + 2px)}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block}.col-form-label{padding-top:calc(.5rem - 1px * 2);padding-bottom:calc(.5rem - 1px * 2);margin-bottom:0}.col-form-label-lg{padding-top:calc(.5rem - 1px * 2);padding-bottom:calc(.5rem - 1px * 2);font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem - 1px * 2);padding-bottom:calc(.25rem - 1px * 2);font-size:.875rem}.col-form-legend{padding-top:.5rem;padding-bottom:.5rem;margin-bottom:0;font-size:1rem}.form-control-plaintext{padding-top:.5rem;padding-bottom:.5rem;margin-bottom:0;line-height:1.25;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm,.input-group-lg>.form-control-plaintext.form-control,.input-group-lg>.form-control-plaintext.input-group-addon,.input-group-lg>.input-group-btn>.form-control-plaintext.btn,.input-group-sm>.form-control-plaintext.form-control,.input-group-sm>.form-control-plaintext.input-group-addon,.input-group-sm>.input-group-btn>.form-control-plaintext.btn{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-sm>.input-group-btn>select.btn:not([size]):not([multiple]),.input-group-sm>select.form-control:not([size]):not([multiple]),.input-group-sm>select.input-group-addon:not([size]):not([multiple]),select.form-control-sm:not([size]):not([multiple]){height:calc(1.8125rem + 2px)}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-lg>.input-group-btn>select.btn:not([size]):not([multiple]),.input-group-lg>select.form-control:not([size]):not([multiple]),.input-group-lg>select.input-group-addon:not([size]):not([multiple]),select.form-control-lg:not([size]):not([multiple]){height:calc(2.3125rem + 2px)}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;margin-bottom:.5rem}.form-check.disabled .form-check-label{color:#868e96}.form-check-label{padding-left:1.25rem;margin-bottom:0}.form-check-input{position:absolute;margin-top:.25rem;margin-left:-1.25rem}.form-check-input:only-child{position:static}.form-check-inline{display:inline-block}.form-check-inline .form-check-label{vertical-align:middle}.form-check-inline+.form-check-inline{margin-left:.75rem}.invalid-feedback{display:none;margin-top:.25rem;font-size:.875rem;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;width:250px;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(220,53,69,.8);border-radius:.2rem}.custom-select.is-valid,.form-control.is-valid,.was-validated .custom-select:valid,.was-validated .form-control:valid{border-color:#28a745}.custom-select.is-valid:focus,.form-control.is-valid:focus,.was-validated .custom-select:valid:focus,.was-validated .form-control:valid:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-valid~.invalid-feedback,.custom-select.is-valid~.invalid-tooltip,.form-control.is-valid~.invalid-feedback,.form-control.is-valid~.invalid-tooltip,.was-validated .custom-select:valid~.invalid-feedback,.was-validated .custom-select:valid~.invalid-tooltip,.was-validated .form-control:valid~.invalid-feedback,.was-validated .form-control:valid~.invalid-tooltip{display:block}.form-check-input.is-valid+.form-check-label,.was-validated .form-check-input:valid+.form-check-label{color:#28a745}.custom-control-input.is-valid~.custom-control-indicator,.was-validated .custom-control-input:valid~.custom-control-indicator{background-color:rgba(40,167,69,.25)}.custom-control-input.is-valid~.custom-control-description,.was-validated .custom-control-input:valid~.custom-control-description{color:#28a745}.custom-file-input.is-valid~.custom-file-control,.was-validated .custom-file-input:valid~.custom-file-control{border-color:#28a745}.custom-file-input.is-valid~.custom-file-control::before,.was-validated .custom-file-input:valid~.custom-file-control::before{border-color:inherit}.custom-file-input.is-valid:focus,.was-validated .custom-file-input:valid:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-invalid,.form-control.is-invalid,.was-validated .custom-select:invalid,.was-validated .form-control:invalid{border-color:#dc3545}.custom-select.is-invalid:focus,.form-control.is-invalid:focus,.was-validated .custom-select:invalid:focus,.was-validated .form-control:invalid:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.form-check-input.is-invalid+.form-check-label,.was-validated .form-check-input:invalid+.form-check-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-indicator,.was-validated .custom-control-input:invalid~.custom-control-indicator{background-color:rgba(220,53,69,.25)}.custom-control-input.is-invalid~.custom-control-description,.was-validated .custom-control-input:invalid~.custom-control-description{color:#dc3545}.custom-file-input.is-invalid~.custom-file-control,.was-validated .custom-file-input:invalid~.custom-file-control{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-control::before,.was-validated .custom-file-input:invalid~.custom-file-control::before{border-color:inherit}.custom-file-input.is-invalid:focus,.was-validated .custom-file-input:invalid:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-ms-flexbox;display:flex;-ms-flex:0 0 auto;flex:0 0 auto;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .input-group{width:auto}.form-inline .form-control-label{margin-bottom:0;vertical-align:middle}.form-inline .form-check{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:auto;margin-top:0;margin-bottom:0}.form-inline .form-check-label{padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;padding-left:0}.form-inline .custom-control-indicator{position:static;display:inline-block;margin-right:.25rem;vertical-align:text-bottom}.form-inline .has-feedback .form-control-feedback{top:0}}.btn{display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:1px solid transparent;padding:.5rem .75rem;font-size:1rem;line-height:1.25;border-radius:.25rem;transition:all .2s ease-in-out}.btn:focus,.btn:hover{text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 3px rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn.active,.btn:active{background-image:none}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 3px rgba(0,123,255,.5)}.btn-primary.disabled,.btn-primary:disabled{background-color:#007bff;border-color:#007bff}.btn-primary.active,.btn-primary:active,.show>.btn-primary.dropdown-toggle{background-color:#0069d9;background-image:none;border-color:#0062cc}.btn-secondary{color:#fff;background-color:#868e96;border-color:#868e96}.btn-secondary:hover{color:#fff;background-color:#727b84;border-color:#6c757d}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 3px rgba(134,142,150,.5)}.btn-secondary.disabled,.btn-secondary:disabled{background-color:#868e96;border-color:#868e96}.btn-secondary.active,.btn-secondary:active,.show>.btn-secondary.dropdown-toggle{background-color:#727b84;background-image:none;border-color:#6c757d}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 3px rgba(40,167,69,.5)}.btn-success.disabled,.btn-success:disabled{background-color:#28a745;border-color:#28a745}.btn-success.active,.btn-success:active,.show>.btn-success.dropdown-toggle{background-color:#218838;background-image:none;border-color:#1e7e34}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 3px rgba(23,162,184,.5)}.btn-info.disabled,.btn-info:disabled{background-color:#17a2b8;border-color:#17a2b8}.btn-info.active,.btn-info:active,.show>.btn-info.dropdown-toggle{background-color:#138496;background-image:none;border-color:#117a8b}.btn-warning{color:#111;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#111;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 3px rgba(255,193,7,.5)}.btn-warning.disabled,.btn-warning:disabled{background-color:#ffc107;border-color:#ffc107}.btn-warning.active,.btn-warning:active,.show>.btn-warning.dropdown-toggle{background-color:#e0a800;background-image:none;border-color:#d39e00}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 3px rgba(220,53,69,.5)}.btn-danger.disabled,.btn-danger:disabled{background-color:#dc3545;border-color:#dc3545}.btn-danger.active,.btn-danger:active,.show>.btn-danger.dropdown-toggle{background-color:#c82333;background-image:none;border-color:#bd2130}.btn-light{color:#111;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#111;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 3px rgba(248,249,250,.5)}.btn-light.disabled,.btn-light:disabled{background-color:#f8f9fa;border-color:#f8f9fa}.btn-light.active,.btn-light:active,.show>.btn-light.dropdown-toggle{background-color:#e2e6ea;background-image:none;border-color:#dae0e5}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 3px rgba(52,58,64,.5)}.btn-dark.disabled,.btn-dark:disabled{background-color:#343a40;border-color:#343a40}.btn-dark.active,.btn-dark:active,.show>.btn-dark.dropdown-toggle{background-color:#23272b;background-image:none;border-color:#1d2124}.btn-outline-primary{color:#007bff;background-color:transparent;background-image:none;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 3px rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary.active,.btn-outline-primary:active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-secondary{color:#868e96;background-color:transparent;background-image:none;border-color:#868e96}.btn-outline-secondary:hover{color:#fff;background-color:#868e96;border-color:#868e96}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 3px rgba(134,142,150,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#868e96;background-color:transparent}.btn-outline-secondary.active,.btn-outline-secondary:active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#868e96;border-color:#868e96}.btn-outline-success{color:#28a745;background-color:transparent;background-image:none;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 3px rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success.active,.btn-outline-success:active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-info{color:#17a2b8;background-color:transparent;background-image:none;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 3px rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info.active,.btn-outline-info:active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-warning{color:#ffc107;background-color:transparent;background-image:none;border-color:#ffc107}.btn-outline-warning:hover{color:#fff;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 3px rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning.active,.btn-outline-warning:active,.show>.btn-outline-warning.dropdown-toggle{color:#fff;background-color:#ffc107;border-color:#ffc107}.btn-outline-danger{color:#dc3545;background-color:transparent;background-image:none;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 3px rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger.active,.btn-outline-danger:active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-light{color:#f8f9fa;background-color:transparent;background-image:none;border-color:#f8f9fa}.btn-outline-light:hover{color:#fff;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 3px rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light.active,.btn-outline-light:active,.show>.btn-outline-light.dropdown-toggle{color:#fff;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-dark{color:#343a40;background-color:transparent;background-image:none;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 3px rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark.active,.btn-outline-dark:active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-link{font-weight:400;color:#007bff;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link:disabled{background-color:transparent}.btn-link,.btn-link:active,.btn-link:focus{border-color:transparent}.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#0056b3;text-decoration:underline;background-color:transparent}.btn-link:disabled{color:#868e96}.btn-link:disabled:focus,.btn-link:disabled:hover{text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;transition:opacity .15s linear}.fade.show{opacity:1}.collapse{display:none}.collapse.show{display:block}tr.collapse.show{display:table-row}tbody.collapse.show{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}.dropdown,.dropup{position:relative}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropup .dropdown-toggle::after{border-top:0;border-bottom:.3em solid}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background:0 0;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#868e96;background-color:transparent}.show>a{outline:0}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#868e96;white-space:nowrap}.btn-group,.btn-group-vertical{position:relative;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-ms-flex:0 1 auto;flex:0 1 auto;margin-bottom:0}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:2}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn+.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.btn+.dropdown-toggle-split::after{margin-left:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:center;justify-content:center}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-ms-flexbox;display:flex;width:100%}.input-group .form-control{position:relative;z-index:2;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;margin-bottom:0}.input-group .form-control:active,.input-group .form-control:focus,.input-group .form-control:hover{z-index:3}.input-group .form-control,.input-group-addon,.input-group-btn{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{white-space:nowrap;vertical-align:middle}.input-group-addon{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.25;color:#495057;text-align:center;background-color:#e9ecef;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.input-group-addon.form-control-sm,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.input-group-addon.btn{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.input-group-addon.form-control-lg,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.input-group-addon.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:not(:last-child),.input-group-addon:not(:last-child),.input-group-btn:not(:first-child)>.btn-group:not(:last-child)>.btn,.input-group-btn:not(:first-child)>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:not(:last-child)>.btn,.input-group-btn:not(:last-child)>.btn-group>.btn,.input-group-btn:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:not(:last-child){border-right:0}.input-group .form-control:not(:first-child),.input-group-addon:not(:first-child),.input-group-btn:not(:first-child)>.btn,.input-group-btn:not(:first-child)>.btn-group>.btn,.input-group-btn:not(:first-child)>.dropdown-toggle,.input-group-btn:not(:last-child)>.btn-group:not(:first-child)>.btn,.input-group-btn:not(:last-child)>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.form-control+.input-group-addon:not(:first-child){border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:3}.input-group-btn:not(:last-child)>.btn,.input-group-btn:not(:last-child)>.btn-group{margin-right:-1px}.input-group-btn:not(:first-child)>.btn,.input-group-btn:not(:first-child)>.btn-group{z-index:2;margin-left:-1px}.input-group-btn:not(:first-child)>.btn-group:active,.input-group-btn:not(:first-child)>.btn-group:focus,.input-group-btn:not(:first-child)>.btn-group:hover,.input-group-btn:not(:first-child)>.btn:active,.input-group-btn:not(:first-child)>.btn:focus,.input-group-btn:not(:first-child)>.btn:hover{z-index:3}.custom-control{position:relative;display:-ms-inline-flexbox;display:inline-flex;min-height:1.5rem;padding-left:1.5rem;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-indicator{color:#fff;background-color:#007bff}.custom-control-input:focus~.custom-control-indicator{box-shadow:0 0 0 1px #fff,0 0 0 3px #007bff}.custom-control-input:active~.custom-control-indicator{color:#fff;background-color:#b3d7ff}.custom-control-input:disabled~.custom-control-indicator{background-color:#e9ecef}.custom-control-input:disabled~.custom-control-description{color:#868e96}.custom-control-indicator{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#ddd;background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-indicator{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-indicator{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-indicator{background-color:#007bff;background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-radio .custom-control-indicator{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-indicator{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-controls-stacked{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.custom-controls-stacked .custom-control{margin-bottom:.25rem}.custom-controls-stacked .custom-control+.custom-control{margin-left:0}.custom-select{display:inline-block;max-width:100%;height:calc(2.25rem + 2px);padding:.375rem 1.75rem .375rem .75rem;line-height:1.25;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23333' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;background-size:8px 10px;border:1px solid rgba(0,0,0,.15);border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select:disabled{color:#868e96;background-color:#e9ecef}.custom-select::-ms-expand{opacity:0}.custom-select-sm{height:calc(1.8125rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:75%}.custom-file{position:relative;display:inline-block;max-width:100%;height:2.5rem;margin-bottom:0}.custom-file-input{min-width:14rem;max-width:100%;height:2.5rem;margin:0;opacity:0}.custom-file-control{position:absolute;top:0;right:0;left:0;z-index:5;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#495057;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#fff;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.custom-file-control:lang(en):empty::after{content:"Choose file..."}.custom-file-control::before{position:absolute;top:-1px;right:-1px;bottom:-1px;z-index:6;display:block;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#495057;background-color:#e9ecef;border:1px solid rgba(0,0,0,.15);border-radius:0 .25rem .25rem 0}.custom-file-control:lang(en)::before{content:"Browse"}.nav{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#868e96}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #ddd}.nav-tabs .nav-link.disabled{color:#868e96;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#ddd #ddd #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.show>.nav-pills .nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}@media (max-width:575px){.navbar>.container,.navbar>.container-fluid{width:100%;margin-right:0;margin-left:0}}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background:0 0;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-ms-flexbox!important;display:flex!important}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:-ms-flexbox!important;display:flex!important}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:-ms-flexbox!important;display:flex!important}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:-ms-flexbox!important;display:flex!important}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:-ms-flexbox!important;display:flex!important}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.card{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}@media (min-width:576px){.card-deck{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:-ms-flexbox;display:flex;-ms-flex:1 0 0%;flex:1 0 0%;-ms-flex-direction:column;flex-direction:column;margin-right:15px;margin-left:15px}}@media (min-width:576px){.card-group{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group .card{-ms-flex:1 0 0%;flex:1 0 0%}.card-group .card+.card{margin-left:0;border-left:0}.card-group .card:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.card-group .card:first-child .card-img-top{border-top-right-radius:0}.card-group .card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group .card:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.card-group .card:last-child .card-img-top{border-top-left-radius:0}.card-group .card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group .card:not(:first-child):not(:last-child){border-radius:0}.card-group .card:not(:first-child):not(:last-child) .card-img-bottom,.card-group .card:not(:first-child):not(:last-child) .card-img-top{border-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{-webkit-column-count:3;column-count:3;-webkit-column-gap:1.25rem;column-gap:1.25rem}.card-columns .card{display:inline-block;width:100%}}.breadcrumb{padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb::after{display:block;clear:both;content:""}.breadcrumb-item{float:left}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;padding-left:.5rem;color:#868e96;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#868e96}.pagination{display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#868e96;pointer-events:none;background-color:#fff;border-color:#ddd}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #ddd}.page-link:focus,.page-link:hover{color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#ddd}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}.badge-primary[href]:focus,.badge-primary[href]:hover{color:#fff;text-decoration:none;background-color:#0062cc}.badge-secondary{color:#fff;background-color:#868e96}.badge-secondary[href]:focus,.badge-secondary[href]:hover{color:#fff;text-decoration:none;background-color:#6c757d}.badge-success{color:#fff;background-color:#28a745}.badge-success[href]:focus,.badge-success[href]:hover{color:#fff;text-decoration:none;background-color:#1e7e34}.badge-info{color:#fff;background-color:#17a2b8}.badge-info[href]:focus,.badge-info[href]:hover{color:#fff;text-decoration:none;background-color:#117a8b}.badge-warning{color:#111;background-color:#ffc107}.badge-warning[href]:focus,.badge-warning[href]:hover{color:#111;text-decoration:none;background-color:#d39e00}.badge-danger{color:#fff;background-color:#dc3545}.badge-danger[href]:focus,.badge-danger[href]:hover{color:#fff;text-decoration:none;background-color:#bd2130}.badge-light{color:#111;background-color:#f8f9fa}.badge-light[href]:focus,.badge-light[href]:hover{color:#111;text-decoration:none;background-color:#dae0e5}.badge-dark{color:#fff;background-color:#343a40}.badge-dark[href]:focus,.badge-dark[href]:hover{color:#fff;text-decoration:none;background-color:#1d2124}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible .close{position:relative;top:-.75rem;right:-1.25rem;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#464a4e;background-color:#e7e8ea;border-color:#dddfe2}.alert-secondary hr{border-top-color:#cfd2d6}.alert-secondary .alert-link{color:#2e3133}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:-ms-flexbox;display:flex;overflow:hidden;font-size:.75rem;line-height:1rem;text-align:center;background-color:#e9ecef;border-radius:.25rem}.progress-bar{height:1rem;line-height:1rem;color:#fff;background-color:#007bff;transition:width .6s ease}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:progress-bar-stripes 1s linear infinite;animation:progress-bar-stripes 1s linear infinite}.media{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start}.media-body{-ms-flex:1;flex:1}.list-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item:focus,.list-group-item:hover{text-decoration:none}.list-group-item.disabled,.list-group-item:disabled{color:#868e96;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}.list-group-item-primary{color:#004085;background-color:#b8daff}a.list-group-item-primary,button.list-group-item-primary{color:#004085}a.list-group-item-primary:focus,a.list-group-item-primary:hover,button.list-group-item-primary:focus,button.list-group-item-primary:hover{color:#004085;background-color:#9fcdff}a.list-group-item-primary.active,button.list-group-item-primary.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#464a4e;background-color:#dddfe2}a.list-group-item-secondary,button.list-group-item-secondary{color:#464a4e}a.list-group-item-secondary:focus,a.list-group-item-secondary:hover,button.list-group-item-secondary:focus,button.list-group-item-secondary:hover{color:#464a4e;background-color:#cfd2d6}a.list-group-item-secondary.active,button.list-group-item-secondary.active{color:#fff;background-color:#464a4e;border-color:#464a4e}.list-group-item-success{color:#155724;background-color:#c3e6cb}a.list-group-item-success,button.list-group-item-success{color:#155724}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#155724;background-color:#b1dfbb}a.list-group-item-success.active,button.list-group-item-success.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}a.list-group-item-info,button.list-group-item-info{color:#0c5460}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#0c5460;background-color:#abdde5}a.list-group-item-info.active,button.list-group-item-info.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}a.list-group-item-warning,button.list-group-item-warning{color:#856404}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#856404;background-color:#ffe8a1}a.list-group-item-warning.active,button.list-group-item-warning.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}a.list-group-item-danger,button.list-group-item-danger{color:#721c24}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#721c24;background-color:#f1b0b7}a.list-group-item-danger.active,button.list-group-item-danger.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}a.list-group-item-light,button.list-group-item-light{color:#818182}a.list-group-item-light:focus,a.list-group-item-light:hover,button.list-group-item-light:focus,button.list-group-item-light:hover{color:#818182;background-color:#ececf6}a.list-group-item-light.active,button.list-group-item-light.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}a.list-group-item-dark,button.list-group-item-dark{color:#1b1e21}a.list-group-item-dark:focus,a.list-group-item-dark:hover,button.list-group-item-dark:focus,button.list-group-item-dark:hover{color:#1b1e21;background-color:#b9bbbe}a.list-group-item-dark.active,button.list-group-item-dark.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.857143%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:focus,.close:hover{color:#000;text-decoration:none;opacity:.75}button.close{padding:0;background:0 0;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;outline:0}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.show .modal-dialog{-webkit-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;padding:15px;border-bottom:1px solid #e9ecef}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;padding:15px}.modal-footer{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:end;justify-content:flex-end;padding:15px;border-top:1px solid #e9ecef}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:30px auto}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg{max-width:800px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:5px;height:5px}.tooltip.bs-tooltip-auto[x-placement^=top],.tooltip.bs-tooltip-top{padding:5px 0}.tooltip.bs-tooltip-auto[x-placement^=top] .arrow,.tooltip.bs-tooltip-top .arrow{bottom:0}.tooltip.bs-tooltip-auto[x-placement^=top] .arrow::before,.tooltip.bs-tooltip-top .arrow::before{margin-left:-3px;content:"";border-width:5px 5px 0;border-top-color:#000}.tooltip.bs-tooltip-auto[x-placement^=right],.tooltip.bs-tooltip-right{padding:0 5px}.tooltip.bs-tooltip-auto[x-placement^=right] .arrow,.tooltip.bs-tooltip-right .arrow{left:0}.tooltip.bs-tooltip-auto[x-placement^=right] .arrow::before,.tooltip.bs-tooltip-right .arrow::before{margin-top:-3px;content:"";border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.bs-tooltip-auto[x-placement^=bottom],.tooltip.bs-tooltip-bottom{padding:5px 0}.tooltip.bs-tooltip-auto[x-placement^=bottom] .arrow,.tooltip.bs-tooltip-bottom .arrow{top:0}.tooltip.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.tooltip.bs-tooltip-bottom .arrow::before{margin-left:-3px;content:"";border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bs-tooltip-auto[x-placement^=left],.tooltip.bs-tooltip-left{padding:0 5px}.tooltip.bs-tooltip-auto[x-placement^=left] .arrow,.tooltip.bs-tooltip-left .arrow{right:0}.tooltip.bs-tooltip-auto[x-placement^=left] .arrow::before,.tooltip.bs-tooltip-left .arrow::before{right:0;margin-top:-3px;content:"";border-width:5px 0 5px 5px;border-left-color:#000}.tooltip .arrow::before{position:absolute;border-color:transparent;border-style:solid}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;padding:1px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:10px;height:5px}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;border-color:transparent;border-style:solid}.popover .arrow::before{content:"";border-width:11px}.popover .arrow::after{content:"";border-width:11px}.popover.bs-popover-auto[x-placement^=top],.popover.bs-popover-top{margin-bottom:10px}.popover.bs-popover-auto[x-placement^=top] .arrow,.popover.bs-popover-top .arrow{bottom:0}.popover.bs-popover-auto[x-placement^=top] .arrow::after,.popover.bs-popover-auto[x-placement^=top] .arrow::before,.popover.bs-popover-top .arrow::after,.popover.bs-popover-top .arrow::before{border-bottom-width:0}.popover.bs-popover-auto[x-placement^=top] .arrow::before,.popover.bs-popover-top .arrow::before{bottom:-11px;margin-left:-6px;border-top-color:rgba(0,0,0,.25)}.popover.bs-popover-auto[x-placement^=top] .arrow::after,.popover.bs-popover-top .arrow::after{bottom:-10px;margin-left:-6px;border-top-color:#fff}.popover.bs-popover-auto[x-placement^=right],.popover.bs-popover-right{margin-left:10px}.popover.bs-popover-auto[x-placement^=right] .arrow,.popover.bs-popover-right .arrow{left:0}.popover.bs-popover-auto[x-placement^=right] .arrow::after,.popover.bs-popover-auto[x-placement^=right] .arrow::before,.popover.bs-popover-right .arrow::after,.popover.bs-popover-right .arrow::before{margin-top:-8px;border-left-width:0}.popover.bs-popover-auto[x-placement^=right] .arrow::before,.popover.bs-popover-right .arrow::before{left:-11px;border-right-color:rgba(0,0,0,.25)}.popover.bs-popover-auto[x-placement^=right] .arrow::after,.popover.bs-popover-right .arrow::after{left:-10px;border-right-color:#fff}.popover.bs-popover-auto[x-placement^=bottom],.popover.bs-popover-bottom{margin-top:10px}.popover.bs-popover-auto[x-placement^=bottom] .arrow,.popover.bs-popover-bottom .arrow{top:0}.popover.bs-popover-auto[x-placement^=bottom] .arrow::after,.popover.bs-popover-auto[x-placement^=bottom] .arrow::before,.popover.bs-popover-bottom .arrow::after,.popover.bs-popover-bottom .arrow::before{margin-left:-7px;border-top-width:0}.popover.bs-popover-auto[x-placement^=bottom] .arrow::before,.popover.bs-popover-bottom .arrow::before{top:-11px;border-bottom-color:rgba(0,0,0,.25)}.popover.bs-popover-auto[x-placement^=bottom] .arrow::after,.popover.bs-popover-bottom .arrow::after{top:-10px;border-bottom-color:#fff}.popover.bs-popover-auto[x-placement^=bottom] .popover-header::before,.popover.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:20px;margin-left:-10px;content:"";border-bottom:1px solid #f7f7f7}.popover.bs-popover-auto[x-placement^=left],.popover.bs-popover-left{margin-right:10px}.popover.bs-popover-auto[x-placement^=left] .arrow,.popover.bs-popover-left .arrow{right:0}.popover.bs-popover-auto[x-placement^=left] .arrow::after,.popover.bs-popover-auto[x-placement^=left] .arrow::before,.popover.bs-popover-left .arrow::after,.popover.bs-popover-left .arrow::before{margin-top:-8px;border-right-width:0}.popover.bs-popover-auto[x-placement^=left] .arrow::before,.popover.bs-popover-left .arrow::before{right:-11px;border-left-color:rgba(0,0,0,.25)}.popover.bs-popover-auto[x-placement^=left] .arrow::after,.popover.bs-popover-left .arrow::after{right:-10px;border-left-color:#fff}.popover-header{padding:8px 14px;margin-bottom:0;font-size:1rem;color:inherit;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:9px 14px;color:#212529}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-item{position:relative;display:none;-ms-flex-align:center;align-items:center;width:100%;transition:-webkit-transform .6s ease;transition:transform .6s ease;transition:transform .6s ease,-webkit-transform .6s ease;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.carousel-item-next,.carousel-item-prev{position:absolute;top:0}.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translateX(0);transform:translateX(0)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.active.carousel-item-right,.carousel-item-next{-webkit-transform:translateX(100%);transform:translateX(100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-right,.carousel-item-next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translateX(-100%);transform:translateX(-100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:transparent no-repeat center center;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M4 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M1.5 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{position:absolute;right:0;bottom:10px;left:0;z-index:15;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{position:relative;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;background-color:rgba(255,255,255,.5)}.carousel-indicators li::before{position:absolute;top:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators li::after{position:absolute;bottom:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#868e96!important}a.bg-secondary:focus,a.bg-secondary:hover{background-color:#6c757d!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover{background-color:#1d2124!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #e9ecef!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#868e96!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-circle{border-radius:50%}.rounded-0{border-radius:0}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-cell{display:table-cell!important}.d-flex{display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}.d-print-block{display:none!important}@media print{.d-print-block{display:block!important}}.d-print-inline{display:none!important}@media print{.d-print-inline{display:inline!important}}.d-print-inline-block{display:none!important}@media print{.d-print-inline-block{display:inline-block!important}}@media print{.d-print-none{display:none!important}}.flex-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-sm-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-md-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-lg-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-xl-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;-webkit-clip-path:inset(50%);clip-path:inset(50%);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal;-webkit-clip-path:none;clip-path:none}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.m-0{margin:0!important}.mt-0{margin-top:0!important}.mr-0{margin-right:0!important}.mb-0{margin-bottom:0!important}.ml-0{margin-left:0!important}.mx-0{margin-right:0!important;margin-left:0!important}.my-0{margin-top:0!important;margin-bottom:0!important}.m-1{margin:.25rem!important}.mt-1{margin-top:.25rem!important}.mr-1{margin-right:.25rem!important}.mb-1{margin-bottom:.25rem!important}.ml-1{margin-left:.25rem!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-2{margin:.5rem!important}.mt-2{margin-top:.5rem!important}.mr-2{margin-right:.5rem!important}.mb-2{margin-bottom:.5rem!important}.ml-2{margin-left:.5rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-3{margin:1rem!important}.mt-3{margin-top:1rem!important}.mr-3{margin-right:1rem!important}.mb-3{margin-bottom:1rem!important}.ml-3{margin-left:1rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-4{margin:1.5rem!important}.mt-4{margin-top:1.5rem!important}.mr-4{margin-right:1.5rem!important}.mb-4{margin-bottom:1.5rem!important}.ml-4{margin-left:1.5rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-5{margin:3rem!important}.mt-5{margin-top:3rem!important}.mr-5{margin-right:3rem!important}.mb-5{margin-bottom:3rem!important}.ml-5{margin-left:3rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-0{padding:0!important}.pt-0{padding-top:0!important}.pr-0{padding-right:0!important}.pb-0{padding-bottom:0!important}.pl-0{padding-left:0!important}.px-0{padding-right:0!important;padding-left:0!important}.py-0{padding-top:0!important;padding-bottom:0!important}.p-1{padding:.25rem!important}.pt-1{padding-top:.25rem!important}.pr-1{padding-right:.25rem!important}.pb-1{padding-bottom:.25rem!important}.pl-1{padding-left:.25rem!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-2{padding:.5rem!important}.pt-2{padding-top:.5rem!important}.pr-2{padding-right:.5rem!important}.pb-2{padding-bottom:.5rem!important}.pl-2{padding-left:.5rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-3{padding:1rem!important}.pt-3{padding-top:1rem!important}.pr-3{padding-right:1rem!important}.pb-3{padding-bottom:1rem!important}.pl-3{padding-left:1rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-4{padding:1.5rem!important}.pt-4{padding-top:1.5rem!important}.pr-4{padding-right:1.5rem!important}.pb-4{padding-bottom:1.5rem!important}.pl-4{padding-left:1.5rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-5{padding:3rem!important}.pt-5{padding-top:3rem!important}.pr-5{padding-right:3rem!important}.pb-5{padding-bottom:3rem!important}.pl-5{padding-left:3rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-auto{margin:auto!important}.mt-auto{margin-top:auto!important}.mr-auto{margin-right:auto!important}.mb-auto{margin-bottom:auto!important}.ml-auto{margin-left:auto!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0{margin-top:0!important}.mr-sm-0{margin-right:0!important}.mb-sm-0{margin-bottom:0!important}.ml-sm-0{margin-left:0!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1{margin-top:.25rem!important}.mr-sm-1{margin-right:.25rem!important}.mb-sm-1{margin-bottom:.25rem!important}.ml-sm-1{margin-left:.25rem!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2{margin-top:.5rem!important}.mr-sm-2{margin-right:.5rem!important}.mb-sm-2{margin-bottom:.5rem!important}.ml-sm-2{margin-left:.5rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3{margin-top:1rem!important}.mr-sm-3{margin-right:1rem!important}.mb-sm-3{margin-bottom:1rem!important}.ml-sm-3{margin-left:1rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4{margin-top:1.5rem!important}.mr-sm-4{margin-right:1.5rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.ml-sm-4{margin-left:1.5rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5{margin-top:3rem!important}.mr-sm-5{margin-right:3rem!important}.mb-sm-5{margin-bottom:3rem!important}.ml-sm-5{margin-left:3rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0{padding-top:0!important}.pr-sm-0{padding-right:0!important}.pb-sm-0{padding-bottom:0!important}.pl-sm-0{padding-left:0!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1{padding-top:.25rem!important}.pr-sm-1{padding-right:.25rem!important}.pb-sm-1{padding-bottom:.25rem!important}.pl-sm-1{padding-left:.25rem!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2{padding-top:.5rem!important}.pr-sm-2{padding-right:.5rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pl-sm-2{padding-left:.5rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3{padding-top:1rem!important}.pr-sm-3{padding-right:1rem!important}.pb-sm-3{padding-bottom:1rem!important}.pl-sm-3{padding-left:1rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4{padding-top:1.5rem!important}.pr-sm-4{padding-right:1.5rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pl-sm-4{padding-left:1.5rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5{padding-top:3rem!important}.pr-sm-5{padding-right:3rem!important}.pb-sm-5{padding-bottom:3rem!important}.pl-sm-5{padding-left:3rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto{margin-top:auto!important}.mr-sm-auto{margin-right:auto!important}.mb-sm-auto{margin-bottom:auto!important}.ml-sm-auto{margin-left:auto!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0{margin-top:0!important}.mr-md-0{margin-right:0!important}.mb-md-0{margin-bottom:0!important}.ml-md-0{margin-left:0!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.m-md-1{margin:.25rem!important}.mt-md-1{margin-top:.25rem!important}.mr-md-1{margin-right:.25rem!important}.mb-md-1{margin-bottom:.25rem!important}.ml-md-1{margin-left:.25rem!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2{margin-top:.5rem!important}.mr-md-2{margin-right:.5rem!important}.mb-md-2{margin-bottom:.5rem!important}.ml-md-2{margin-left:.5rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3{margin-top:1rem!important}.mr-md-3{margin-right:1rem!important}.mb-md-3{margin-bottom:1rem!important}.ml-md-3{margin-left:1rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4{margin-top:1.5rem!important}.mr-md-4{margin-right:1.5rem!important}.mb-md-4{margin-bottom:1.5rem!important}.ml-md-4{margin-left:1.5rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5{margin-top:3rem!important}.mr-md-5{margin-right:3rem!important}.mb-md-5{margin-bottom:3rem!important}.ml-md-5{margin-left:3rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-md-0{padding:0!important}.pt-md-0{padding-top:0!important}.pr-md-0{padding-right:0!important}.pb-md-0{padding-bottom:0!important}.pl-md-0{padding-left:0!important}.px-md-0{padding-right:0!important;padding-left:0!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.p-md-1{padding:.25rem!important}.pt-md-1{padding-top:.25rem!important}.pr-md-1{padding-right:.25rem!important}.pb-md-1{padding-bottom:.25rem!important}.pl-md-1{padding-left:.25rem!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2{padding-top:.5rem!important}.pr-md-2{padding-right:.5rem!important}.pb-md-2{padding-bottom:.5rem!important}.pl-md-2{padding-left:.5rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3{padding-top:1rem!important}.pr-md-3{padding-right:1rem!important}.pb-md-3{padding-bottom:1rem!important}.pl-md-3{padding-left:1rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4{padding-top:1.5rem!important}.pr-md-4{padding-right:1.5rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pl-md-4{padding-left:1.5rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5{padding-top:3rem!important}.pr-md-5{padding-right:3rem!important}.pb-md-5{padding-bottom:3rem!important}.pl-md-5{padding-left:3rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto{margin-top:auto!important}.mr-md-auto{margin-right:auto!important}.mb-md-auto{margin-bottom:auto!important}.ml-md-auto{margin-left:auto!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0{margin-top:0!important}.mr-lg-0{margin-right:0!important}.mb-lg-0{margin-bottom:0!important}.ml-lg-0{margin-left:0!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1{margin-top:.25rem!important}.mr-lg-1{margin-right:.25rem!important}.mb-lg-1{margin-bottom:.25rem!important}.ml-lg-1{margin-left:.25rem!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2{margin-top:.5rem!important}.mr-lg-2{margin-right:.5rem!important}.mb-lg-2{margin-bottom:.5rem!important}.ml-lg-2{margin-left:.5rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3{margin-top:1rem!important}.mr-lg-3{margin-right:1rem!important}.mb-lg-3{margin-bottom:1rem!important}.ml-lg-3{margin-left:1rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4{margin-top:1.5rem!important}.mr-lg-4{margin-right:1.5rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.ml-lg-4{margin-left:1.5rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5{margin-top:3rem!important}.mr-lg-5{margin-right:3rem!important}.mb-lg-5{margin-bottom:3rem!important}.ml-lg-5{margin-left:3rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0{padding-top:0!important}.pr-lg-0{padding-right:0!important}.pb-lg-0{padding-bottom:0!important}.pl-lg-0{padding-left:0!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1{padding-top:.25rem!important}.pr-lg-1{padding-right:.25rem!important}.pb-lg-1{padding-bottom:.25rem!important}.pl-lg-1{padding-left:.25rem!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2{padding-top:.5rem!important}.pr-lg-2{padding-right:.5rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pl-lg-2{padding-left:.5rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3{padding-top:1rem!important}.pr-lg-3{padding-right:1rem!important}.pb-lg-3{padding-bottom:1rem!important}.pl-lg-3{padding-left:1rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4{padding-top:1.5rem!important}.pr-lg-4{padding-right:1.5rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pl-lg-4{padding-left:1.5rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5{padding-top:3rem!important}.pr-lg-5{padding-right:3rem!important}.pb-lg-5{padding-bottom:3rem!important}.pl-lg-5{padding-left:3rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto{margin-top:auto!important}.mr-lg-auto{margin-right:auto!important}.mb-lg-auto{margin-bottom:auto!important}.ml-lg-auto{margin-left:auto!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0{margin-top:0!important}.mr-xl-0{margin-right:0!important}.mb-xl-0{margin-bottom:0!important}.ml-xl-0{margin-left:0!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1{margin-top:.25rem!important}.mr-xl-1{margin-right:.25rem!important}.mb-xl-1{margin-bottom:.25rem!important}.ml-xl-1{margin-left:.25rem!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2{margin-top:.5rem!important}.mr-xl-2{margin-right:.5rem!important}.mb-xl-2{margin-bottom:.5rem!important}.ml-xl-2{margin-left:.5rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3{margin-top:1rem!important}.mr-xl-3{margin-right:1rem!important}.mb-xl-3{margin-bottom:1rem!important}.ml-xl-3{margin-left:1rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4{margin-top:1.5rem!important}.mr-xl-4{margin-right:1.5rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.ml-xl-4{margin-left:1.5rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5{margin-top:3rem!important}.mr-xl-5{margin-right:3rem!important}.mb-xl-5{margin-bottom:3rem!important}.ml-xl-5{margin-left:3rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0{padding-top:0!important}.pr-xl-0{padding-right:0!important}.pb-xl-0{padding-bottom:0!important}.pl-xl-0{padding-left:0!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1{padding-top:.25rem!important}.pr-xl-1{padding-right:.25rem!important}.pb-xl-1{padding-bottom:.25rem!important}.pl-xl-1{padding-left:.25rem!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2{padding-top:.5rem!important}.pr-xl-2{padding-right:.5rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pl-xl-2{padding-left:.5rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3{padding-top:1rem!important}.pr-xl-3{padding-right:1rem!important}.pb-xl-3{padding-bottom:1rem!important}.pl-xl-3{padding-left:1rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4{padding-top:1.5rem!important}.pr-xl-4{padding-right:1.5rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pl-xl-4{padding-left:1.5rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5{padding-top:3rem!important}.pr-xl-5{padding-right:3rem!important}.pb-xl-5{padding-bottom:3rem!important}.pl-xl-5{padding-left:3rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto{margin-top:auto!important}.mr-xl-auto{margin-right:auto!important}.mb-xl-auto{margin-bottom:auto!important}.ml-xl-auto{margin-left:auto!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-normal{font-weight:400}.font-weight-bold{font-weight:700}.font-italic{font-style:italic}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0062cc!important}.text-secondary{color:#868e96!important}a.text-secondary:focus,a.text-secondary:hover{color:#6c757d!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#1e7e34!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#117a8b!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#d39e00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#bd2130!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#dae0e5!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#1d2124!important}.text-muted{color:#ced4da!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.visible{visibility:visible!important}.invisible{visibility:hidden!important}
+ */@media print{*,::after,::before,blockquote::first-letter,blockquote::first-line,div::first-letter,div::first-line,li::first-letter,li::first-line,p::first-letter,p::first-line{text-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}html{box-sizing:border-box;font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}*,::after,::before{box-sizing:inherit}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}[role=button],a,area,button,input,label,select,summary,textarea{-ms-touch-action:manipulation;touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#868e96;text-align:left;caption-side:bottom}th{text-align:left}label{display:inline-block;margin-bottom:.5rem}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.1}.display-2{font-size:5.5rem;font-weight:300;line-height:1.1}.display-3{font-size:4.5rem;font-weight:300;line-height:1.1}.display-4{font-size:3.5rem;font-weight:300;line-height:1.1}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:5px}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#868e96}.blockquote-footer::before{content:"\2014 \00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #ddd;border-radius:.25rem;transition:all .2s ease-in-out;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#868e96}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}code{padding:.2rem .4rem;font-size:90%;color:#bd4147;background-color:#f8f9fa;border-radius:.25rem}a>code{padding:0;color:inherit;background-color:inherit}kbd{padding:.2rem .4rem;font-size:90%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;margin-top:0;margin-bottom:1rem;font-size:90%;color:#212529}pre code{padding:0;font-size:inherit;color:inherit;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-right:15px;padding-left:15px}@media (min-width:576px){.container{width:540px;max-width:100%}}@media (min-width:768px){.container{width:720px;max-width:100%}}@media (min-width:992px){.container{width:960px;max-width:100%}}@media (min-width:1200px){.container{width:1140px;max-width:100%}}.container-fluid{width:100%;margin-right:auto;margin-left:auto;padding-right:15px;padding-left:15px}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-9{-ms-flex-order:9;order:9}.order-10{-ms-flex-order:10;order:10}.order-11{-ms-flex-order:11;order:11}.order-12{-ms-flex-order:12;order:12}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-sm-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-1{-ms-flex-order:1;order:1}.order-sm-2{-ms-flex-order:2;order:2}.order-sm-3{-ms-flex-order:3;order:3}.order-sm-4{-ms-flex-order:4;order:4}.order-sm-5{-ms-flex-order:5;order:5}.order-sm-6{-ms-flex-order:6;order:6}.order-sm-7{-ms-flex-order:7;order:7}.order-sm-8{-ms-flex-order:8;order:8}.order-sm-9{-ms-flex-order:9;order:9}.order-sm-10{-ms-flex-order:10;order:10}.order-sm-11{-ms-flex-order:11;order:11}.order-sm-12{-ms-flex-order:12;order:12}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-md-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-1{-ms-flex-order:1;order:1}.order-md-2{-ms-flex-order:2;order:2}.order-md-3{-ms-flex-order:3;order:3}.order-md-4{-ms-flex-order:4;order:4}.order-md-5{-ms-flex-order:5;order:5}.order-md-6{-ms-flex-order:6;order:6}.order-md-7{-ms-flex-order:7;order:7}.order-md-8{-ms-flex-order:8;order:8}.order-md-9{-ms-flex-order:9;order:9}.order-md-10{-ms-flex-order:10;order:10}.order-md-11{-ms-flex-order:11;order:11}.order-md-12{-ms-flex-order:12;order:12}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-lg-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-1{-ms-flex-order:1;order:1}.order-lg-2{-ms-flex-order:2;order:2}.order-lg-3{-ms-flex-order:3;order:3}.order-lg-4{-ms-flex-order:4;order:4}.order-lg-5{-ms-flex-order:5;order:5}.order-lg-6{-ms-flex-order:6;order:6}.order-lg-7{-ms-flex-order:7;order:7}.order-lg-8{-ms-flex-order:8;order:8}.order-lg-9{-ms-flex-order:9;order:9}.order-lg-10{-ms-flex-order:10;order:10}.order-lg-11{-ms-flex-order:11;order:11}.order-lg-12{-ms-flex-order:12;order:12}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-xl-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-1{-ms-flex-order:1;order:1}.order-xl-2{-ms-flex-order:2;order:2}.order-xl-3{-ms-flex-order:3;order:3}.order-xl-4{-ms-flex-order:4;order:4}.order-xl-5{-ms-flex-order:5;order:5}.order-xl-6{-ms-flex-order:6;order:6}.order-xl-7{-ms-flex-order:7;order:7}.order-xl-8{-ms-flex-order:8;order:8}.order-xl-9{-ms-flex-order:9;order:9}.order-xl-10{-ms-flex-order:10;order:10}.order-xl-11{-ms-flex-order:11;order:11}.order-xl-12{-ms-flex-order:12;order:12}}.table{width:100%;max-width:100%;margin-bottom:1rem;background-color:transparent}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #e9ecef}.table thead th{vertical-align:bottom;border-bottom:2px solid #e9ecef}.table tbody+tbody{border-top:2px solid #e9ecef}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #e9ecef}.table-bordered td,.table-bordered th{border:1px solid #e9ecef}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#dddfe2}.table-hover .table-secondary:hover{background-color:#cfd2d6}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#cfd2d6}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.thead-inverse th{color:#fff;background-color:#212529}.thead-default th{color:#495057;background-color:#e9ecef}.table-inverse{color:#fff;background-color:#212529}.table-inverse td,.table-inverse th,.table-inverse thead th{border-color:#32383e}.table-inverse.table-bordered{border:0}.table-inverse.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-inverse.table-hover tbody tr:hover{background-color:rgba(255,255,255,.075)}@media (max-width:991px){.table-responsive{display:block;width:100%;overflow-x:auto;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive.table-bordered{border:0}}.form-control{display:block;width:100%;padding:.5rem .75rem;font-size:1rem;line-height:1.25;color:#495057;background-color:#fff;background-image:none;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0}.form-control::-webkit-input-placeholder{color:#868e96;opacity:1}.form-control::-moz-placeholder{color:#868e96;opacity:1}.form-control:-ms-input-placeholder{color:#868e96;opacity:1}.form-control::placeholder{color:#868e96;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:not([size]):not([multiple]){height:calc(2.25rem + 2px)}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block}.col-form-label{padding-top:calc(.5rem - 1px * 2);padding-bottom:calc(.5rem - 1px * 2);margin-bottom:0}.col-form-label-lg{padding-top:calc(.5rem - 1px * 2);padding-bottom:calc(.5rem - 1px * 2);font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem - 1px * 2);padding-bottom:calc(.25rem - 1px * 2);font-size:.875rem}.col-form-legend{padding-top:.5rem;padding-bottom:.5rem;margin-bottom:0;font-size:1rem}.form-control-plaintext{padding-top:.5rem;padding-bottom:.5rem;margin-bottom:0;line-height:1.25;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm,.input-group-lg>.form-control-plaintext.form-control,.input-group-lg>.form-control-plaintext.input-group-addon,.input-group-lg>.input-group-btn>.form-control-plaintext.btn,.input-group-sm>.form-control-plaintext.form-control,.input-group-sm>.form-control-plaintext.input-group-addon,.input-group-sm>.input-group-btn>.form-control-plaintext.btn{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-sm>.input-group-btn>select.btn:not([size]):not([multiple]),.input-group-sm>select.form-control:not([size]):not([multiple]),.input-group-sm>select.input-group-addon:not([size]):not([multiple]),select.form-control-sm:not([size]):not([multiple]){height:calc(1.8125rem + 2px)}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-lg>.input-group-btn>select.btn:not([size]):not([multiple]),.input-group-lg>select.form-control:not([size]):not([multiple]),.input-group-lg>select.input-group-addon:not([size]):not([multiple]),select.form-control-lg:not([size]):not([multiple]){height:calc(2.3125rem + 2px)}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;margin-bottom:.5rem}.form-check.disabled .form-check-label{color:#868e96}.form-check-label{padding-left:1.25rem;margin-bottom:0}.form-check-input{position:absolute;margin-top:.25rem;margin-left:-1.25rem}.form-check-input:only-child{position:static}.form-check-inline{display:inline-block}.form-check-inline .form-check-label{vertical-align:middle}.form-check-inline+.form-check-inline{margin-left:.75rem}.invalid-feedback{display:none;margin-top:.25rem;font-size:.875rem;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;width:250px;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(220,53,69,.8);border-radius:.2rem}.custom-select.is-valid,.form-control.is-valid,.was-validated .custom-select:valid,.was-validated .form-control:valid{border-color:#28a745}.custom-select.is-valid:focus,.form-control.is-valid:focus,.was-validated .custom-select:valid:focus,.was-validated .form-control:valid:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-valid~.invalid-feedback,.custom-select.is-valid~.invalid-tooltip,.form-control.is-valid~.invalid-feedback,.form-control.is-valid~.invalid-tooltip,.was-validated .custom-select:valid~.invalid-feedback,.was-validated .custom-select:valid~.invalid-tooltip,.was-validated .form-control:valid~.invalid-feedback,.was-validated .form-control:valid~.invalid-tooltip{display:block}.form-check-input.is-valid+.form-check-label,.was-validated .form-check-input:valid+.form-check-label{color:#28a745}.custom-control-input.is-valid~.custom-control-indicator,.was-validated .custom-control-input:valid~.custom-control-indicator{background-color:rgba(40,167,69,.25)}.custom-control-input.is-valid~.custom-control-description,.was-validated .custom-control-input:valid~.custom-control-description{color:#28a745}.custom-file-input.is-valid~.custom-file-control,.was-validated .custom-file-input:valid~.custom-file-control{border-color:#28a745}.custom-file-input.is-valid~.custom-file-control::before,.was-validated .custom-file-input:valid~.custom-file-control::before{border-color:inherit}.custom-file-input.is-valid:focus,.was-validated .custom-file-input:valid:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-invalid,.form-control.is-invalid,.was-validated .custom-select:invalid,.was-validated .form-control:invalid{border-color:#dc3545}.custom-select.is-invalid:focus,.form-control.is-invalid:focus,.was-validated .custom-select:invalid:focus,.was-validated .form-control:invalid:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.form-check-input.is-invalid+.form-check-label,.was-validated .form-check-input:invalid+.form-check-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-indicator,.was-validated .custom-control-input:invalid~.custom-control-indicator{background-color:rgba(220,53,69,.25)}.custom-control-input.is-invalid~.custom-control-description,.was-validated .custom-control-input:invalid~.custom-control-description{color:#dc3545}.custom-file-input.is-invalid~.custom-file-control,.was-validated .custom-file-input:invalid~.custom-file-control{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-control::before,.was-validated .custom-file-input:invalid~.custom-file-control::before{border-color:inherit}.custom-file-input.is-invalid:focus,.was-validated .custom-file-input:invalid:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-ms-flexbox;display:flex;-ms-flex:0 0 auto;flex:0 0 auto;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .input-group{width:auto}.form-inline .form-control-label{margin-bottom:0;vertical-align:middle}.form-inline .form-check{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:auto;margin-top:0;margin-bottom:0}.form-inline .form-check-label{padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;padding-left:0}.form-inline .custom-control-indicator{position:static;display:inline-block;margin-right:.25rem;vertical-align:text-bottom}.form-inline .has-feedback .form-control-feedback{top:0}}.btn{display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:1px solid transparent;padding:.5rem .75rem;font-size:1rem;line-height:1.25;border-radius:.25rem;transition:all .15s ease-in-out}.btn:focus,.btn:hover{text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 3px rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn.active,.btn:active{background-image:none}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 3px rgba(0,123,255,.5)}.btn-primary.disabled,.btn-primary:disabled{background-color:#007bff;border-color:#007bff}.btn-primary.active,.btn-primary:active,.show>.btn-primary.dropdown-toggle{background-color:#0069d9;background-image:none;border-color:#0062cc}.btn-secondary{color:#fff;background-color:#868e96;border-color:#868e96}.btn-secondary:hover{color:#fff;background-color:#727b84;border-color:#6c757d}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 3px rgba(134,142,150,.5)}.btn-secondary.disabled,.btn-secondary:disabled{background-color:#868e96;border-color:#868e96}.btn-secondary.active,.btn-secondary:active,.show>.btn-secondary.dropdown-toggle{background-color:#727b84;background-image:none;border-color:#6c757d}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 3px rgba(40,167,69,.5)}.btn-success.disabled,.btn-success:disabled{background-color:#28a745;border-color:#28a745}.btn-success.active,.btn-success:active,.show>.btn-success.dropdown-toggle{background-color:#218838;background-image:none;border-color:#1e7e34}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 3px rgba(23,162,184,.5)}.btn-info.disabled,.btn-info:disabled{background-color:#17a2b8;border-color:#17a2b8}.btn-info.active,.btn-info:active,.show>.btn-info.dropdown-toggle{background-color:#138496;background-image:none;border-color:#117a8b}.btn-warning{color:#111;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#111;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 3px rgba(255,193,7,.5)}.btn-warning.disabled,.btn-warning:disabled{background-color:#ffc107;border-color:#ffc107}.btn-warning.active,.btn-warning:active,.show>.btn-warning.dropdown-toggle{background-color:#e0a800;background-image:none;border-color:#d39e00}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 3px rgba(220,53,69,.5)}.btn-danger.disabled,.btn-danger:disabled{background-color:#dc3545;border-color:#dc3545}.btn-danger.active,.btn-danger:active,.show>.btn-danger.dropdown-toggle{background-color:#c82333;background-image:none;border-color:#bd2130}.btn-light{color:#111;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#111;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 3px rgba(248,249,250,.5)}.btn-light.disabled,.btn-light:disabled{background-color:#f8f9fa;border-color:#f8f9fa}.btn-light.active,.btn-light:active,.show>.btn-light.dropdown-toggle{background-color:#e2e6ea;background-image:none;border-color:#dae0e5}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 3px rgba(52,58,64,.5)}.btn-dark.disabled,.btn-dark:disabled{background-color:#343a40;border-color:#343a40}.btn-dark.active,.btn-dark:active,.show>.btn-dark.dropdown-toggle{background-color:#23272b;background-image:none;border-color:#1d2124}.btn-outline-primary{color:#007bff;background-color:transparent;background-image:none;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 3px rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary.active,.btn-outline-primary:active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-secondary{color:#868e96;background-color:transparent;background-image:none;border-color:#868e96}.btn-outline-secondary:hover{color:#fff;background-color:#868e96;border-color:#868e96}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 3px rgba(134,142,150,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#868e96;background-color:transparent}.btn-outline-secondary.active,.btn-outline-secondary:active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#868e96;border-color:#868e96}.btn-outline-success{color:#28a745;background-color:transparent;background-image:none;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 3px rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success.active,.btn-outline-success:active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-info{color:#17a2b8;background-color:transparent;background-image:none;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 3px rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info.active,.btn-outline-info:active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-warning{color:#ffc107;background-color:transparent;background-image:none;border-color:#ffc107}.btn-outline-warning:hover{color:#fff;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 3px rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning.active,.btn-outline-warning:active,.show>.btn-outline-warning.dropdown-toggle{color:#fff;background-color:#ffc107;border-color:#ffc107}.btn-outline-danger{color:#dc3545;background-color:transparent;background-image:none;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 3px rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger.active,.btn-outline-danger:active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-light{color:#f8f9fa;background-color:transparent;background-image:none;border-color:#f8f9fa}.btn-outline-light:hover{color:#fff;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 3px rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light.active,.btn-outline-light:active,.show>.btn-outline-light.dropdown-toggle{color:#fff;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-dark{color:#343a40;background-color:transparent;background-image:none;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 3px rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark.active,.btn-outline-dark:active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-link{font-weight:400;color:#007bff;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link:disabled{background-color:transparent}.btn-link,.btn-link:active,.btn-link:focus{border-color:transparent}.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#0056b3;text-decoration:underline;background-color:transparent}.btn-link:disabled{color:#868e96}.btn-link:disabled:focus,.btn-link:disabled:hover{text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;transition:opacity .15s linear}.fade.show{opacity:1}.collapse{display:none}.collapse.show{display:block}tr.collapse.show{display:table-row}tbody.collapse.show{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}.dropdown,.dropup{position:relative}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropup .dropdown-toggle::after{border-top:0;border-bottom:.3em solid}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background:0 0;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#868e96;background-color:transparent}.show>a{outline:0}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#868e96;white-space:nowrap}.btn-group,.btn-group-vertical{position:relative;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-ms-flex:0 1 auto;flex:0 1 auto;margin-bottom:0}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:2}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn+.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.btn+.dropdown-toggle-split::after{margin-left:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:center;justify-content:center}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-ms-flexbox;display:flex;width:100%}.input-group .form-control{position:relative;z-index:2;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;margin-bottom:0}.input-group .form-control:active,.input-group .form-control:focus,.input-group .form-control:hover{z-index:3}.input-group .form-control,.input-group-addon,.input-group-btn{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{white-space:nowrap;vertical-align:middle}.input-group-addon{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.25;color:#495057;text-align:center;background-color:#e9ecef;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.input-group-addon.form-control-sm,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.input-group-addon.btn{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.input-group-addon.form-control-lg,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.input-group-addon.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:not(:last-child),.input-group-addon:not(:last-child),.input-group-btn:not(:first-child)>.btn-group:not(:last-child)>.btn,.input-group-btn:not(:first-child)>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:not(:last-child)>.btn,.input-group-btn:not(:last-child)>.btn-group>.btn,.input-group-btn:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:not(:last-child){border-right:0}.input-group .form-control:not(:first-child),.input-group-addon:not(:first-child),.input-group-btn:not(:first-child)>.btn,.input-group-btn:not(:first-child)>.btn-group>.btn,.input-group-btn:not(:first-child)>.dropdown-toggle,.input-group-btn:not(:last-child)>.btn-group:not(:first-child)>.btn,.input-group-btn:not(:last-child)>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.form-control+.input-group-addon:not(:first-child){border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:3}.input-group-btn:not(:last-child)>.btn,.input-group-btn:not(:last-child)>.btn-group{margin-right:-1px}.input-group-btn:not(:first-child)>.btn,.input-group-btn:not(:first-child)>.btn-group{z-index:2;margin-left:-1px}.input-group-btn:not(:first-child)>.btn-group:active,.input-group-btn:not(:first-child)>.btn-group:focus,.input-group-btn:not(:first-child)>.btn-group:hover,.input-group-btn:not(:first-child)>.btn:active,.input-group-btn:not(:first-child)>.btn:focus,.input-group-btn:not(:first-child)>.btn:hover{z-index:3}.custom-control{position:relative;display:-ms-inline-flexbox;display:inline-flex;min-height:1.5rem;padding-left:1.5rem;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-indicator{color:#fff;background-color:#007bff}.custom-control-input:focus~.custom-control-indicator{box-shadow:0 0 0 1px #fff,0 0 0 3px #007bff}.custom-control-input:active~.custom-control-indicator{color:#fff;background-color:#b3d7ff}.custom-control-input:disabled~.custom-control-indicator{background-color:#e9ecef}.custom-control-input:disabled~.custom-control-description{color:#868e96}.custom-control-indicator{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#ddd;background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-indicator{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-indicator{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-indicator{background-color:#007bff;background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-radio .custom-control-indicator{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-indicator{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-controls-stacked{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.custom-controls-stacked .custom-control{margin-bottom:.25rem}.custom-controls-stacked .custom-control+.custom-control{margin-left:0}.custom-select{display:inline-block;max-width:100%;height:calc(2.25rem + 2px);padding:.375rem 1.75rem .375rem .75rem;line-height:1.25;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23333' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;background-size:8px 10px;border:1px solid rgba(0,0,0,.15);border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select:disabled{color:#868e96;background-color:#e9ecef}.custom-select::-ms-expand{opacity:0}.custom-select-sm{height:calc(1.8125rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:75%}.custom-file{position:relative;display:inline-block;max-width:100%;height:2.5rem;margin-bottom:0}.custom-file-input{min-width:14rem;max-width:100%;height:2.5rem;margin:0;opacity:0}.custom-file-control{position:absolute;top:0;right:0;left:0;z-index:5;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#495057;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#fff;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.custom-file-control:lang(en):empty::after{content:"Choose file..."}.custom-file-control::before{position:absolute;top:-1px;right:-1px;bottom:-1px;z-index:6;display:block;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#495057;background-color:#e9ecef;border:1px solid rgba(0,0,0,.15);border-radius:0 .25rem .25rem 0}.custom-file-control:lang(en)::before{content:"Browse"}.nav{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#868e96}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #ddd}.nav-tabs .nav-link.disabled{color:#868e96;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#ddd #ddd #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.show>.nav-pills .nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}@media (max-width:575px){.navbar>.container,.navbar>.container-fluid{width:100%;margin-right:0;margin-left:0}}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background:0 0;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-ms-flexbox!important;display:flex!important}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:-ms-flexbox!important;display:flex!important}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:-ms-flexbox!important;display:flex!important}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:-ms-flexbox!important;display:flex!important}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:-ms-flexbox!important;display:flex!important}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.card{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}@media (min-width:576px){.card-deck{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:-ms-flexbox;display:flex;-ms-flex:1 0 0%;flex:1 0 0%;-ms-flex-direction:column;flex-direction:column;margin-right:15px;margin-left:15px}}@media (min-width:576px){.card-group{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group .card{-ms-flex:1 0 0%;flex:1 0 0%}.card-group .card+.card{margin-left:0;border-left:0}.card-group .card:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.card-group .card:first-child .card-img-top{border-top-right-radius:0}.card-group .card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group .card:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.card-group .card:last-child .card-img-top{border-top-left-radius:0}.card-group .card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group .card:not(:first-child):not(:last-child){border-radius:0}.card-group .card:not(:first-child):not(:last-child) .card-img-bottom,.card-group .card:not(:first-child):not(:last-child) .card-img-top{border-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem}.card-columns .card{display:inline-block;width:100%}}.breadcrumb{padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb::after{display:block;clear:both;content:""}.breadcrumb-item{float:left}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;padding-left:.5rem;color:#868e96;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#868e96}.pagination{display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#868e96;pointer-events:none;background-color:#fff;border-color:#ddd}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #ddd}.page-link:focus,.page-link:hover{color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#ddd}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}.badge-primary[href]:focus,.badge-primary[href]:hover{color:#fff;text-decoration:none;background-color:#0062cc}.badge-secondary{color:#fff;background-color:#868e96}.badge-secondary[href]:focus,.badge-secondary[href]:hover{color:#fff;text-decoration:none;background-color:#6c757d}.badge-success{color:#fff;background-color:#28a745}.badge-success[href]:focus,.badge-success[href]:hover{color:#fff;text-decoration:none;background-color:#1e7e34}.badge-info{color:#fff;background-color:#17a2b8}.badge-info[href]:focus,.badge-info[href]:hover{color:#fff;text-decoration:none;background-color:#117a8b}.badge-warning{color:#111;background-color:#ffc107}.badge-warning[href]:focus,.badge-warning[href]:hover{color:#111;text-decoration:none;background-color:#d39e00}.badge-danger{color:#fff;background-color:#dc3545}.badge-danger[href]:focus,.badge-danger[href]:hover{color:#fff;text-decoration:none;background-color:#bd2130}.badge-light{color:#111;background-color:#f8f9fa}.badge-light[href]:focus,.badge-light[href]:hover{color:#111;text-decoration:none;background-color:#dae0e5}.badge-dark{color:#fff;background-color:#343a40}.badge-dark[href]:focus,.badge-dark[href]:hover{color:#fff;text-decoration:none;background-color:#1d2124}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible .close{position:relative;top:-.75rem;right:-1.25rem;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#464a4e;background-color:#e7e8ea;border-color:#dddfe2}.alert-secondary hr{border-top-color:#cfd2d6}.alert-secondary .alert-link{color:#2e3133}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:-ms-flexbox;display:flex;overflow:hidden;font-size:.75rem;line-height:1rem;text-align:center;background-color:#e9ecef;border-radius:.25rem}.progress-bar{height:1rem;line-height:1rem;color:#fff;background-color:#007bff;transition:width .6s ease}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:progress-bar-stripes 1s linear infinite;animation:progress-bar-stripes 1s linear infinite}.media{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start}.media-body{-ms-flex:1;flex:1}.list-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item:focus,.list-group-item:hover{text-decoration:none}.list-group-item.disabled,.list-group-item:disabled{color:#868e96;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}.list-group-item-primary{color:#004085;background-color:#b8daff}a.list-group-item-primary,button.list-group-item-primary{color:#004085}a.list-group-item-primary:focus,a.list-group-item-primary:hover,button.list-group-item-primary:focus,button.list-group-item-primary:hover{color:#004085;background-color:#9fcdff}a.list-group-item-primary.active,button.list-group-item-primary.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#464a4e;background-color:#dddfe2}a.list-group-item-secondary,button.list-group-item-secondary{color:#464a4e}a.list-group-item-secondary:focus,a.list-group-item-secondary:hover,button.list-group-item-secondary:focus,button.list-group-item-secondary:hover{color:#464a4e;background-color:#cfd2d6}a.list-group-item-secondary.active,button.list-group-item-secondary.active{color:#fff;background-color:#464a4e;border-color:#464a4e}.list-group-item-success{color:#155724;background-color:#c3e6cb}a.list-group-item-success,button.list-group-item-success{color:#155724}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#155724;background-color:#b1dfbb}a.list-group-item-success.active,button.list-group-item-success.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}a.list-group-item-info,button.list-group-item-info{color:#0c5460}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#0c5460;background-color:#abdde5}a.list-group-item-info.active,button.list-group-item-info.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}a.list-group-item-warning,button.list-group-item-warning{color:#856404}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#856404;background-color:#ffe8a1}a.list-group-item-warning.active,button.list-group-item-warning.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}a.list-group-item-danger,button.list-group-item-danger{color:#721c24}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#721c24;background-color:#f1b0b7}a.list-group-item-danger.active,button.list-group-item-danger.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}a.list-group-item-light,button.list-group-item-light{color:#818182}a.list-group-item-light:focus,a.list-group-item-light:hover,button.list-group-item-light:focus,button.list-group-item-light:hover{color:#818182;background-color:#ececf6}a.list-group-item-light.active,button.list-group-item-light.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}a.list-group-item-dark,button.list-group-item-dark{color:#1b1e21}a.list-group-item-dark:focus,a.list-group-item-dark:hover,button.list-group-item-dark:focus,button.list-group-item-dark:hover{color:#1b1e21;background-color:#b9bbbe}a.list-group-item-dark.active,button.list-group-item-dark.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:focus,.close:hover{color:#000;text-decoration:none;opacity:.75}button.close{padding:0;background:0 0;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;outline:0}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.show .modal-dialog{-webkit-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;padding:15px;border-bottom:1px solid #e9ecef}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;padding:15px}.modal-footer{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:end;justify-content:flex-end;padding:15px;border-top:1px solid #e9ecef}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:30px auto}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg{max-width:800px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:5px;height:5px}.tooltip.bs-tooltip-auto[x-placement^=top],.tooltip.bs-tooltip-top{padding:5px 0}.tooltip.bs-tooltip-auto[x-placement^=top] .arrow,.tooltip.bs-tooltip-top .arrow{bottom:0}.tooltip.bs-tooltip-auto[x-placement^=top] .arrow::before,.tooltip.bs-tooltip-top .arrow::before{margin-left:-3px;content:"";border-width:5px 5px 0;border-top-color:#000}.tooltip.bs-tooltip-auto[x-placement^=right],.tooltip.bs-tooltip-right{padding:0 5px}.tooltip.bs-tooltip-auto[x-placement^=right] .arrow,.tooltip.bs-tooltip-right .arrow{left:0}.tooltip.bs-tooltip-auto[x-placement^=right] .arrow::before,.tooltip.bs-tooltip-right .arrow::before{margin-top:-3px;content:"";border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.bs-tooltip-auto[x-placement^=bottom],.tooltip.bs-tooltip-bottom{padding:5px 0}.tooltip.bs-tooltip-auto[x-placement^=bottom] .arrow,.tooltip.bs-tooltip-bottom .arrow{top:0}.tooltip.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.tooltip.bs-tooltip-bottom .arrow::before{margin-left:-3px;content:"";border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bs-tooltip-auto[x-placement^=left],.tooltip.bs-tooltip-left{padding:0 5px}.tooltip.bs-tooltip-auto[x-placement^=left] .arrow,.tooltip.bs-tooltip-left .arrow{right:0}.tooltip.bs-tooltip-auto[x-placement^=left] .arrow::before,.tooltip.bs-tooltip-left .arrow::before{right:0;margin-top:-3px;content:"";border-width:5px 0 5px 5px;border-left-color:#000}.tooltip .arrow::before{position:absolute;border-color:transparent;border-style:solid}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;padding:1px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:10px;height:5px}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;border-color:transparent;border-style:solid}.popover .arrow::before{content:"";border-width:11px}.popover .arrow::after{content:"";border-width:11px}.popover.bs-popover-auto[x-placement^=top],.popover.bs-popover-top{margin-bottom:10px}.popover.bs-popover-auto[x-placement^=top] .arrow,.popover.bs-popover-top .arrow{bottom:0}.popover.bs-popover-auto[x-placement^=top] .arrow::after,.popover.bs-popover-auto[x-placement^=top] .arrow::before,.popover.bs-popover-top .arrow::after,.popover.bs-popover-top .arrow::before{border-bottom-width:0}.popover.bs-popover-auto[x-placement^=top] .arrow::before,.popover.bs-popover-top .arrow::before{bottom:-11px;margin-left:-6px;border-top-color:rgba(0,0,0,.25)}.popover.bs-popover-auto[x-placement^=top] .arrow::after,.popover.bs-popover-top .arrow::after{bottom:-10px;margin-left:-6px;border-top-color:#fff}.popover.bs-popover-auto[x-placement^=right],.popover.bs-popover-right{margin-left:10px}.popover.bs-popover-auto[x-placement^=right] .arrow,.popover.bs-popover-right .arrow{left:0}.popover.bs-popover-auto[x-placement^=right] .arrow::after,.popover.bs-popover-auto[x-placement^=right] .arrow::before,.popover.bs-popover-right .arrow::after,.popover.bs-popover-right .arrow::before{margin-top:-8px;border-left-width:0}.popover.bs-popover-auto[x-placement^=right] .arrow::before,.popover.bs-popover-right .arrow::before{left:-11px;border-right-color:rgba(0,0,0,.25)}.popover.bs-popover-auto[x-placement^=right] .arrow::after,.popover.bs-popover-right .arrow::after{left:-10px;border-right-color:#fff}.popover.bs-popover-auto[x-placement^=bottom],.popover.bs-popover-bottom{margin-top:10px}.popover.bs-popover-auto[x-placement^=bottom] .arrow,.popover.bs-popover-bottom .arrow{top:0}.popover.bs-popover-auto[x-placement^=bottom] .arrow::after,.popover.bs-popover-auto[x-placement^=bottom] .arrow::before,.popover.bs-popover-bottom .arrow::after,.popover.bs-popover-bottom .arrow::before{margin-left:-7px;border-top-width:0}.popover.bs-popover-auto[x-placement^=bottom] .arrow::before,.popover.bs-popover-bottom .arrow::before{top:-11px;border-bottom-color:rgba(0,0,0,.25)}.popover.bs-popover-auto[x-placement^=bottom] .arrow::after,.popover.bs-popover-bottom .arrow::after{top:-10px;border-bottom-color:#fff}.popover.bs-popover-auto[x-placement^=bottom] .popover-header::before,.popover.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:20px;margin-left:-10px;content:"";border-bottom:1px solid #f7f7f7}.popover.bs-popover-auto[x-placement^=left],.popover.bs-popover-left{margin-right:10px}.popover.bs-popover-auto[x-placement^=left] .arrow,.popover.bs-popover-left .arrow{right:0}.popover.bs-popover-auto[x-placement^=left] .arrow::after,.popover.bs-popover-auto[x-placement^=left] .arrow::before,.popover.bs-popover-left .arrow::after,.popover.bs-popover-left .arrow::before{margin-top:-8px;border-right-width:0}.popover.bs-popover-auto[x-placement^=left] .arrow::before,.popover.bs-popover-left .arrow::before{right:-11px;border-left-color:rgba(0,0,0,.25)}.popover.bs-popover-auto[x-placement^=left] .arrow::after,.popover.bs-popover-left .arrow::after{right:-10px;border-left-color:#fff}.popover-header{padding:8px 14px;margin-bottom:0;font-size:1rem;color:inherit;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:9px 14px;color:#212529}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-item{position:relative;display:none;-ms-flex-align:center;align-items:center;width:100%;transition:-webkit-transform .6s ease;transition:transform .6s ease;transition:transform .6s ease,-webkit-transform .6s ease;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.carousel-item-next,.carousel-item-prev{position:absolute;top:0}.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translateX(0);transform:translateX(0)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.active.carousel-item-right,.carousel-item-next{-webkit-transform:translateX(100%);transform:translateX(100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-right,.carousel-item-next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translateX(-100%);transform:translateX(-100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:transparent no-repeat center center;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M4 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M1.5 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{position:absolute;right:0;bottom:10px;left:0;z-index:15;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{position:relative;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;background-color:rgba(255,255,255,.5)}.carousel-indicators li::before{position:absolute;top:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators li::after{position:absolute;bottom:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#868e96!important}a.bg-secondary:focus,a.bg-secondary:hover{background-color:#6c757d!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover{background-color:#1d2124!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #e9ecef!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#868e96!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-circle{border-radius:50%}.rounded-0{border-radius:0}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-cell{display:table-cell!important}.d-flex{display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}.d-print-block{display:none!important}@media print{.d-print-block{display:block!important}}.d-print-inline{display:none!important}@media print{.d-print-inline{display:inline!important}}.d-print-inline-block{display:none!important}@media print{.d-print-inline-block{display:inline-block!important}}@media print{.d-print-none{display:none!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.857143%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-sm-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-md-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-lg-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-xl-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;-webkit-clip-path:inset(50%);clip-path:inset(50%);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal;-webkit-clip-path:none;clip-path:none}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.m-0{margin:0!important}.mt-0{margin-top:0!important}.mr-0{margin-right:0!important}.mb-0{margin-bottom:0!important}.ml-0{margin-left:0!important}.mx-0{margin-right:0!important;margin-left:0!important}.my-0{margin-top:0!important;margin-bottom:0!important}.m-1{margin:.25rem!important}.mt-1{margin-top:.25rem!important}.mr-1{margin-right:.25rem!important}.mb-1{margin-bottom:.25rem!important}.ml-1{margin-left:.25rem!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-2{margin:.5rem!important}.mt-2{margin-top:.5rem!important}.mr-2{margin-right:.5rem!important}.mb-2{margin-bottom:.5rem!important}.ml-2{margin-left:.5rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-3{margin:1rem!important}.mt-3{margin-top:1rem!important}.mr-3{margin-right:1rem!important}.mb-3{margin-bottom:1rem!important}.ml-3{margin-left:1rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-4{margin:1.5rem!important}.mt-4{margin-top:1.5rem!important}.mr-4{margin-right:1.5rem!important}.mb-4{margin-bottom:1.5rem!important}.ml-4{margin-left:1.5rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-5{margin:3rem!important}.mt-5{margin-top:3rem!important}.mr-5{margin-right:3rem!important}.mb-5{margin-bottom:3rem!important}.ml-5{margin-left:3rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-0{padding:0!important}.pt-0{padding-top:0!important}.pr-0{padding-right:0!important}.pb-0{padding-bottom:0!important}.pl-0{padding-left:0!important}.px-0{padding-right:0!important;padding-left:0!important}.py-0{padding-top:0!important;padding-bottom:0!important}.p-1{padding:.25rem!important}.pt-1{padding-top:.25rem!important}.pr-1{padding-right:.25rem!important}.pb-1{padding-bottom:.25rem!important}.pl-1{padding-left:.25rem!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-2{padding:.5rem!important}.pt-2{padding-top:.5rem!important}.pr-2{padding-right:.5rem!important}.pb-2{padding-bottom:.5rem!important}.pl-2{padding-left:.5rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-3{padding:1rem!important}.pt-3{padding-top:1rem!important}.pr-3{padding-right:1rem!important}.pb-3{padding-bottom:1rem!important}.pl-3{padding-left:1rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-4{padding:1.5rem!important}.pt-4{padding-top:1.5rem!important}.pr-4{padding-right:1.5rem!important}.pb-4{padding-bottom:1.5rem!important}.pl-4{padding-left:1.5rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-5{padding:3rem!important}.pt-5{padding-top:3rem!important}.pr-5{padding-right:3rem!important}.pb-5{padding-bottom:3rem!important}.pl-5{padding-left:3rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-auto{margin:auto!important}.mt-auto{margin-top:auto!important}.mr-auto{margin-right:auto!important}.mb-auto{margin-bottom:auto!important}.ml-auto{margin-left:auto!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0{margin-top:0!important}.mr-sm-0{margin-right:0!important}.mb-sm-0{margin-bottom:0!important}.ml-sm-0{margin-left:0!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1{margin-top:.25rem!important}.mr-sm-1{margin-right:.25rem!important}.mb-sm-1{margin-bottom:.25rem!important}.ml-sm-1{margin-left:.25rem!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2{margin-top:.5rem!important}.mr-sm-2{margin-right:.5rem!important}.mb-sm-2{margin-bottom:.5rem!important}.ml-sm-2{margin-left:.5rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3{margin-top:1rem!important}.mr-sm-3{margin-right:1rem!important}.mb-sm-3{margin-bottom:1rem!important}.ml-sm-3{margin-left:1rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4{margin-top:1.5rem!important}.mr-sm-4{margin-right:1.5rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.ml-sm-4{margin-left:1.5rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5{margin-top:3rem!important}.mr-sm-5{margin-right:3rem!important}.mb-sm-5{margin-bottom:3rem!important}.ml-sm-5{margin-left:3rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0{padding-top:0!important}.pr-sm-0{padding-right:0!important}.pb-sm-0{padding-bottom:0!important}.pl-sm-0{padding-left:0!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1{padding-top:.25rem!important}.pr-sm-1{padding-right:.25rem!important}.pb-sm-1{padding-bottom:.25rem!important}.pl-sm-1{padding-left:.25rem!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2{padding-top:.5rem!important}.pr-sm-2{padding-right:.5rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pl-sm-2{padding-left:.5rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3{padding-top:1rem!important}.pr-sm-3{padding-right:1rem!important}.pb-sm-3{padding-bottom:1rem!important}.pl-sm-3{padding-left:1rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4{padding-top:1.5rem!important}.pr-sm-4{padding-right:1.5rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pl-sm-4{padding-left:1.5rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5{padding-top:3rem!important}.pr-sm-5{padding-right:3rem!important}.pb-sm-5{padding-bottom:3rem!important}.pl-sm-5{padding-left:3rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto{margin-top:auto!important}.mr-sm-auto{margin-right:auto!important}.mb-sm-auto{margin-bottom:auto!important}.ml-sm-auto{margin-left:auto!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0{margin-top:0!important}.mr-md-0{margin-right:0!important}.mb-md-0{margin-bottom:0!important}.ml-md-0{margin-left:0!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.m-md-1{margin:.25rem!important}.mt-md-1{margin-top:.25rem!important}.mr-md-1{margin-right:.25rem!important}.mb-md-1{margin-bottom:.25rem!important}.ml-md-1{margin-left:.25rem!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2{margin-top:.5rem!important}.mr-md-2{margin-right:.5rem!important}.mb-md-2{margin-bottom:.5rem!important}.ml-md-2{margin-left:.5rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3{margin-top:1rem!important}.mr-md-3{margin-right:1rem!important}.mb-md-3{margin-bottom:1rem!important}.ml-md-3{margin-left:1rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4{margin-top:1.5rem!important}.mr-md-4{margin-right:1.5rem!important}.mb-md-4{margin-bottom:1.5rem!important}.ml-md-4{margin-left:1.5rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5{margin-top:3rem!important}.mr-md-5{margin-right:3rem!important}.mb-md-5{margin-bottom:3rem!important}.ml-md-5{margin-left:3rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-md-0{padding:0!important}.pt-md-0{padding-top:0!important}.pr-md-0{padding-right:0!important}.pb-md-0{padding-bottom:0!important}.pl-md-0{padding-left:0!important}.px-md-0{padding-right:0!important;padding-left:0!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.p-md-1{padding:.25rem!important}.pt-md-1{padding-top:.25rem!important}.pr-md-1{padding-right:.25rem!important}.pb-md-1{padding-bottom:.25rem!important}.pl-md-1{padding-left:.25rem!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2{padding-top:.5rem!important}.pr-md-2{padding-right:.5rem!important}.pb-md-2{padding-bottom:.5rem!important}.pl-md-2{padding-left:.5rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3{padding-top:1rem!important}.pr-md-3{padding-right:1rem!important}.pb-md-3{padding-bottom:1rem!important}.pl-md-3{padding-left:1rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4{padding-top:1.5rem!important}.pr-md-4{padding-right:1.5rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pl-md-4{padding-left:1.5rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5{padding-top:3rem!important}.pr-md-5{padding-right:3rem!important}.pb-md-5{padding-bottom:3rem!important}.pl-md-5{padding-left:3rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto{margin-top:auto!important}.mr-md-auto{margin-right:auto!important}.mb-md-auto{margin-bottom:auto!important}.ml-md-auto{margin-left:auto!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0{margin-top:0!important}.mr-lg-0{margin-right:0!important}.mb-lg-0{margin-bottom:0!important}.ml-lg-0{margin-left:0!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1{margin-top:.25rem!important}.mr-lg-1{margin-right:.25rem!important}.mb-lg-1{margin-bottom:.25rem!important}.ml-lg-1{margin-left:.25rem!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2{margin-top:.5rem!important}.mr-lg-2{margin-right:.5rem!important}.mb-lg-2{margin-bottom:.5rem!important}.ml-lg-2{margin-left:.5rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3{margin-top:1rem!important}.mr-lg-3{margin-right:1rem!important}.mb-lg-3{margin-bottom:1rem!important}.ml-lg-3{margin-left:1rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4{margin-top:1.5rem!important}.mr-lg-4{margin-right:1.5rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.ml-lg-4{margin-left:1.5rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5{margin-top:3rem!important}.mr-lg-5{margin-right:3rem!important}.mb-lg-5{margin-bottom:3rem!important}.ml-lg-5{margin-left:3rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0{padding-top:0!important}.pr-lg-0{padding-right:0!important}.pb-lg-0{padding-bottom:0!important}.pl-lg-0{padding-left:0!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1{padding-top:.25rem!important}.pr-lg-1{padding-right:.25rem!important}.pb-lg-1{padding-bottom:.25rem!important}.pl-lg-1{padding-left:.25rem!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2{padding-top:.5rem!important}.pr-lg-2{padding-right:.5rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pl-lg-2{padding-left:.5rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3{padding-top:1rem!important}.pr-lg-3{padding-right:1rem!important}.pb-lg-3{padding-bottom:1rem!important}.pl-lg-3{padding-left:1rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4{padding-top:1.5rem!important}.pr-lg-4{padding-right:1.5rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pl-lg-4{padding-left:1.5rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5{padding-top:3rem!important}.pr-lg-5{padding-right:3rem!important}.pb-lg-5{padding-bottom:3rem!important}.pl-lg-5{padding-left:3rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto{margin-top:auto!important}.mr-lg-auto{margin-right:auto!important}.mb-lg-auto{margin-bottom:auto!important}.ml-lg-auto{margin-left:auto!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0{margin-top:0!important}.mr-xl-0{margin-right:0!important}.mb-xl-0{margin-bottom:0!important}.ml-xl-0{margin-left:0!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1{margin-top:.25rem!important}.mr-xl-1{margin-right:.25rem!important}.mb-xl-1{margin-bottom:.25rem!important}.ml-xl-1{margin-left:.25rem!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2{margin-top:.5rem!important}.mr-xl-2{margin-right:.5rem!important}.mb-xl-2{margin-bottom:.5rem!important}.ml-xl-2{margin-left:.5rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3{margin-top:1rem!important}.mr-xl-3{margin-right:1rem!important}.mb-xl-3{margin-bottom:1rem!important}.ml-xl-3{margin-left:1rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4{margin-top:1.5rem!important}.mr-xl-4{margin-right:1.5rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.ml-xl-4{margin-left:1.5rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5{margin-top:3rem!important}.mr-xl-5{margin-right:3rem!important}.mb-xl-5{margin-bottom:3rem!important}.ml-xl-5{margin-left:3rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0{padding-top:0!important}.pr-xl-0{padding-right:0!important}.pb-xl-0{padding-bottom:0!important}.pl-xl-0{padding-left:0!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1{padding-top:.25rem!important}.pr-xl-1{padding-right:.25rem!important}.pb-xl-1{padding-bottom:.25rem!important}.pl-xl-1{padding-left:.25rem!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2{padding-top:.5rem!important}.pr-xl-2{padding-right:.5rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pl-xl-2{padding-left:.5rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3{padding-top:1rem!important}.pr-xl-3{padding-right:1rem!important}.pb-xl-3{padding-bottom:1rem!important}.pl-xl-3{padding-left:1rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4{padding-top:1.5rem!important}.pr-xl-4{padding-right:1.5rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pl-xl-4{padding-left:1.5rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5{padding-top:3rem!important}.pr-xl-5{padding-right:3rem!important}.pb-xl-5{padding-bottom:3rem!important}.pl-xl-5{padding-left:3rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto{margin-top:auto!important}.mr-xl-auto{margin-right:auto!important}.mb-xl-auto{margin-bottom:auto!important}.ml-xl-auto{margin-left:auto!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-normal{font-weight:400}.font-weight-bold{font-weight:700}.font-italic{font-style:italic}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0062cc!important}.text-secondary{color:#868e96!important}a.text-secondary:focus,a.text-secondary:hover{color:#6c757d!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#1e7e34!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#117a8b!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#d39e00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#bd2130!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#dae0e5!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#1d2124!important}.text-muted{color:#ced4da!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.visible{visibility:visible!important}.invisible{visibility:hidden!important}
/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file
diff --git a/library/bootstrap/css/bootstrap.min.css.map b/library/bootstrap/css/bootstrap.min.css.map
index e8588c31a..86ee215e4 100644
--- a/library/bootstrap/css/bootstrap.min.css.map
+++ b/library/bootstrap/css/bootstrap.min.css.map
@@ -1 +1 @@
-{"version":3,"sources":["../../scss/bootstrap.scss","../../scss/_print.scss","dist/css/bootstrap.css","../../scss/_reboot.scss","bootstrap.css","../../scss/mixins/_hover.scss","../../scss/_type.scss","../../scss/mixins/_lists.scss","../../scss/_images.scss","../../scss/mixins/_image.scss","../../scss/mixins/_border-radius.scss","../../scss/mixins/_transition.scss","../../scss/_code.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/mixins/_breakpoints.scss","../../scss/mixins/_grid-framework.scss","../../scss/_tables.scss","../../scss/mixins/_table-row.scss","../../scss/_forms.scss","../../scss/mixins/_forms.scss","../../scss/_buttons.scss","../../scss/mixins/_buttons.scss","../../scss/_functions.scss","../../scss/_transitions.scss","../../scss/_dropdown.scss","../../scss/mixins/_nav-divider.scss","../../scss/_button-group.scss","../../scss/_input-group.scss","../../scss/_custom-forms.scss","../../scss/_nav.scss","../../scss/_navbar.scss","../../scss/_card.scss","../../scss/_breadcrumb.scss","../../scss/mixins/_clearfix.scss","../../scss/_pagination.scss","../../scss/mixins/_pagination.scss","../../scss/_badge.scss","../../scss/mixins/_badge.scss","../../scss/_jumbotron.scss","../../scss/_alert.scss","../../scss/mixins/_alert.scss","../../scss/_progress.scss","../../scss/mixins/_gradients.scss","../../scss/_media.scss","../../scss/_list-group.scss","../../scss/mixins/_list-group.scss","../../scss/_responsive-embed.scss","../../scss/_close.scss","../../scss/_modal.scss","../../scss/_tooltip.scss","../../scss/mixins/_reset-text.scss","../../scss/_popover.scss","../../scss/_carousel.scss","../../scss/utilities/_align.scss","../../scss/mixins/_background-variant.scss","../../scss/utilities/_background.scss","../../scss/utilities/_borders.scss","../../scss/utilities/_display.scss","../../scss/utilities/_flex.scss","../../scss/utilities/_float.scss","../../scss/mixins/_float.scss","../../scss/utilities/_position.scss","../../scss/utilities/_screenreaders.scss","../../scss/mixins/_screen-reader.scss","../../scss/utilities/_sizing.scss","../../scss/utilities/_spacing.scss","../../scss/utilities/_text.scss","../../scss/mixins/_text-truncate.scss","../../scss/mixins/_text-emphasis.scss","../../scss/mixins/_text-hide.scss","../../scss/utilities/_visibility.scss","../../scss/mixins/_visibility.scss"],"names":[],"mappings":"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"} \ No newline at end of file
+{"version":3,"sources":["../../scss/bootstrap.scss","../../scss/_print.scss","dist/css/bootstrap.css","../../scss/_reboot.scss","bootstrap.css","../../scss/mixins/_hover.scss","../../scss/_type.scss","../../scss/mixins/_lists.scss","../../scss/_images.scss","../../scss/mixins/_image.scss","../../scss/mixins/_border-radius.scss","../../scss/mixins/_transition.scss","../../scss/_code.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/mixins/_breakpoints.scss","../../scss/mixins/_grid-framework.scss","../../scss/_tables.scss","../../scss/mixins/_table-row.scss","../../scss/_forms.scss","../../scss/mixins/_forms.scss","../../scss/_buttons.scss","../../scss/mixins/_buttons.scss","../../scss/_functions.scss","../../scss/_transitions.scss","../../scss/_dropdown.scss","../../scss/mixins/_nav-divider.scss","../../scss/_button-group.scss","../../scss/_input-group.scss","../../scss/_custom-forms.scss","../../scss/_nav.scss","../../scss/_navbar.scss","../../scss/_card.scss","../../scss/_breadcrumb.scss","../../scss/mixins/_clearfix.scss","../../scss/_pagination.scss","../../scss/mixins/_pagination.scss","../../scss/_badge.scss","../../scss/mixins/_badge.scss","../../scss/_jumbotron.scss","../../scss/_alert.scss","../../scss/mixins/_alert.scss","../../scss/_progress.scss","../../scss/mixins/_gradients.scss","../../scss/_media.scss","../../scss/_list-group.scss","../../scss/mixins/_list-group.scss","../../scss/_close.scss","../../scss/_modal.scss","../../scss/_tooltip.scss","../../scss/mixins/_reset-text.scss","../../scss/_popover.scss","../../scss/_carousel.scss","../../scss/utilities/_align.scss","../../scss/mixins/_background-variant.scss","../../scss/utilities/_background.scss","../../scss/utilities/_borders.scss","../../scss/utilities/_display.scss","../../scss/utilities/_embed.scss","../../scss/utilities/_flex.scss","../../scss/utilities/_float.scss","../../scss/mixins/_float.scss","../../scss/utilities/_position.scss","../../scss/utilities/_screenreaders.scss","../../scss/mixins/_screen-reader.scss","../../scss/utilities/_sizing.scss","../../scss/utilities/_spacing.scss","../../scss/utilities/_text.scss","../../scss/mixins/_text-truncate.scss","../../scss/mixins/_text-emphasis.scss","../../scss/mixins/_text-hide.scss","../../scss/utilities/_visibility.scss","../../scss/mixins/_visibility.scss"],"names":[],"mappings":"AAAA;;;;;ACWE,aACE,ECHF,QADA,SAIA,yBAIA,uBALA,kBAIA,gBAFA,iBAIA,eAPA,gBAIA,cDYI,YAAA,eAEA,WAAA,eAGF,ECTF,UDWI,gBAAA,UAQF,mBACE,QAAA,KAAA,YAAA,IAcF,IACE,YAAA,mBCzBJ,WD2BE,IAEE,OAAA,IAAA,MAAA,KACA,kBAAA,MAQF,MACE,QAAA,mBC/BJ,IDkCE,GAEE,kBAAA,MChCJ,GACA,GDkCE,EAGE,QAAA,EACA,OAAA,EAGF,GCpCF,GDsCI,iBAAA,MAMF,QACE,QAAA,KAEF,OACE,OAAA,IAAA,MAAA,KAGF,OACE,gBAAA,mBADF,UCtCF,UD2CM,iBAAA,eCvCN,mBD0CE,mBAGI,OAAA,IAAA,MAAA,gBE5FR,KACE,WAAA,WACA,YAAA,WACA,YAAA,KACA,yBAAA,KACA,qBAAA,KACA,mBAAA,UACA,4BAAA,YAGF,EDsDA,QADA,SClDE,WAAA,QAKA,cAAgB,MAAA,aAIlB,QAAA,MAAA,OAAA,WAAA,OAAA,OAAA,OAAA,OAAA,KAAA,IAAA,QACE,QAAA,MAQF,KACE,OAAA,EACA,YAAA,aAAA,CAAA,kBAAA,CAAA,UAAA,CAAA,MAAA,CAAA,gBAAA,CAAA,KAAA,CAAA,WACA,UAAA,KACA,YAAA,IACA,YAAA,IACA,MAAA,QACA,iBAAA,KCgDF,sBDvCE,QAAA,YASF,GACE,WAAA,YACA,OAAA,EACA,SAAA,QAYF,GAAA,GAAA,GAAA,GAAA,GAAA,GACE,WAAA,EACA,cAAA,MAOF,EACE,WAAA,EACA,cAAA,KDyBF,0BCfA,YAEE,gBAAA,UACA,gBAAA,UAAA,OACA,OAAA,KACA,cAAA,EAGF,QACE,cAAA,KACA,WAAA,OACA,YAAA,QDmBF,GChBA,GDeA,GCZE,WAAA,EACA,cAAA,KAGF,MDgBA,MACA,MAFA,MCXE,cAAA,EAGF,GACE,YAAA,IAGF,GACE,cAAA,MACA,YAAA,EAGF,WACE,OAAA,EAAA,EAAA,KAGF,IACE,WAAA,OAGF,EDeA,OCbE,YAAA,OAGF,MACE,UAAA,IAQF,IDUA,ICRE,SAAA,SACA,UAAA,IACA,YAAA,EACA,eAAA,SAGF,IAAM,OAAA,OACN,IAAM,IAAA,MAON,EACE,MAAA,QACA,gBAAA,KACA,iBAAA,YACA,6BAAA,QEpLE,QFuLA,MAAA,QACA,gBAAA,UAUJ,8BACE,MAAA,QACA,gBAAA,KEzLE,oCAAA,oCF4LA,MAAA,QACA,gBAAA,KANJ,oCAUI,QAAA,EDQJ,KACA,ICAA,IDCA,KCGE,YAAA,SAAA,CAAA,UACA,UAAA,IAGF,IAEE,WAAA,EAEA,cAAA,KAEA,SAAA,KAQF,OAEE,OAAA,EAAA,EAAA,KAQF,IACE,eAAA,OACA,aAAA,KAGF,eACE,SAAA,ODVF,cCwBA,ED1BA,KACA,OAEA,MACA,MACA,OACA,QACA,SC4BE,iBAAA,aAAA,aAAA,aAQF,MACE,gBAAA,SAGF,QACE,YAAA,OACA,eAAA,OACA,MAAA,QACA,WAAA,KACA,aAAA,OAGF,GAEE,WAAA,KAQF,MAEE,QAAA,aACA,cAAA,MAOF,aACE,QAAA,IAAA,OACA,QAAA,IAAA,KAAA,yBDtCF,OCyCA,MDvCA,SADA,OAEA,SC2CE,OAAA,EACA,YAAA,QACA,UAAA,QACA,YAAA,QAGF,ODzCA,MC2CE,SAAA,QAGF,ODzCA,OC2CE,eAAA,KDrCF,aACA,cC0CA,OD5CA,mBCgDE,mBAAA,ODzCF,gCACA,+BACA,gCC2CA,yBAIE,QAAA,EACA,aAAA,KD1CF,qBC6CA,kBAEE,WAAA,WACA,QAAA,EAIF,iBD7CA,2BACA,kBAFA,iBCuDE,mBAAA,QAGF,SACE,SAAA,KAEA,OAAA,SAGF,SAME,UAAA,EAEA,QAAA,EACA,OAAA,EACA,OAAA,EAKF,OACE,QAAA,MACA,MAAA,KACA,UAAA,KACA,QAAA,EACA,cAAA,MACA,UAAA,OACA,YAAA,QACA,MAAA,QACA,YAAA,OAGF,SACE,eAAA,SC3DF,yCFEA,yCC+DE,OAAA,KC5DF,cDoEE,eAAA,KACA,mBAAA,KChEF,4CFEA,yCCuEE,mBAAA,KAQF,6BACE,KAAA,QACA,mBAAA,OAOF,OACE,QAAA,aAGF,QACE,QAAA,UAGF,SACE,QAAA,KC7EF,SDmFE,QAAA,eD7EF,IAAK,IAAK,IAAK,IAAK,IAAK,II9YzB,GAAA,GAAA,GAAA,GAAA,GAAA,GAEE,cAAA,MACA,YAAA,QACA,YAAA,IACA,YAAA,IACA,MAAA,QAGF,IAAA,GAAU,UAAA,OACV,IAAA,GAAU,UAAA,KACV,IAAA,GAAU,UAAA,QACV,IAAA,GAAU,UAAA,OACV,IAAA,GAAU,UAAA,QACV,IAAA,GAAU,UAAA,KAEV,MACE,UAAA,QACA,YAAA,IAIF,WACE,UAAA,KACA,YAAA,IACA,YAAA,IAEF,WACE,UAAA,OACA,YAAA,IACA,YAAA,IAEF,WACE,UAAA,OACA,YAAA,IACA,YAAA,IAEF,WACE,UAAA,OACA,YAAA,IACA,YAAA,IAQF,GACE,WAAA,KACA,cAAA,KACA,OAAA,EACA,WAAA,IAAA,MAAA,eJ+ZF,OIvZA,MAEE,UAAA,IACA,YAAA,IJ0ZF,MIvZA,KAEE,QAAA,KACA,iBAAA,QAQF,eC7EE,aAAA,EACA,WAAA,KDiFF,aClFE,aAAA,EACA,WAAA,KDoFF,kBACE,QAAA,aADF,mCAII,aAAA,IAUJ,YACE,UAAA,IACA,eAAA,UAIF,YACE,cAAA,KACA,UAAA,QAGF,mBACE,QAAA,MACA,UAAA,IACA,MAAA,QAHF,2BAMI,QAAA,cEjHJ,WCIE,UAAA,KAGA,OAAA,KDDF,eACE,QAAA,OACA,iBAAA,KACA,OAAA,IAAA,MAAA,KEZE,cAAA,OCCE,WAAA,IAAA,IAAA,YFMJ,UAAA,KAGA,OAAA,KDeF,QAEE,QAAA,aAGF,YACE,cAAA,MACA,YAAA,EAGF,gBACE,UAAA,IACA,MAAA,QIxCF,KVqiBA,IACA,IACA,KUniBE,YAAA,KAAA,CAAA,MAAA,CAAA,QAAA,CAAA,iBAAA,CAAA,aAAA,CAAA,UAIF,KACE,QAAA,MAAA,MACA,UAAA,IACA,MAAA,QACA,iBAAA,QFTE,cAAA,OEaF,OACE,QAAA,EACA,MAAA,QACA,iBAAA,QAKJ,IACE,QAAA,MAAA,MACA,UAAA,IACA,MAAA,KACA,iBAAA,QFzBE,cAAA,MEqBJ,QASI,QAAA,EACA,UAAA,KACA,YAAA,IAMJ,IACE,QAAA,MACA,WAAA,EACA,cAAA,KACA,UAAA,IACA,MAAA,QALF,SASI,QAAA,EACA,UAAA,QACA,MAAA,QACA,iBAAA,YACA,cAAA,EAKJ,gBACE,WAAA,MACA,WAAA,OCzDA,WCAA,aAAA,KACA,YAAA,KACA,cAAA,KACA,aAAA,KCgDE,yBFnDF,WCWI,MAAA,MACA,UAAA,MCuCF,yBFnDF,WCWI,MAAA,MACA,UAAA,MCuCF,yBFnDF,WCWI,MAAA,MACA,UAAA,MCuCF,0BFnDF,WCWI,MAAA,OACA,UAAA,MDAJ,iBACE,MAAA,KCbF,aAAA,KACA,YAAA,KACA,cAAA,KACA,aAAA,KDoBA,KCLA,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,aAAA,MACA,YAAA,MDQA,YACE,aAAA,EACA,YAAA,EAFF,iBXqnBF,0BW/mBM,cAAA,EACA,aAAA,EGlCJ,KAAA,OAAA,QAAA,QAAA,QAAA,OAAA,OAAA,OAAA,OAAA,OAAA,OAAA,OAAA,OdspBF,UAEqJ,QAAvI,UAAmG,WAAY,WAAY,WAAhH,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UACtG,aAFqJ,QAAvI,UAAmG,WAAY,WAAY,WAAhH,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UACtG,aAFkJ,QAAvI,UAAmG,WAAY,WAAY,WAAhH,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UACnG,aAEqJ,QAAvI,UAAmG,WAAY,WAAY,WAAhH,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UACtG,aczpBI,SAAA,SACA,MAAA,KACA,WAAA,IACA,cAAA,KACA,aAAA,KAmBE,KACE,wBAAA,EAAA,WAAA,EACA,kBAAA,EAAA,UAAA,EACA,UAAA,KAEF,UACE,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,KACA,UAAA,KAIA,OFFN,SAAA,EAAA,EAAA,UAAA,KAAA,EAAA,EAAA,UAIA,UAAA,UEFM,OFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,OFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,OFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,OFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,OFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,OFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,OFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,OFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,QFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,QFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,QFFN,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KAIA,UAAA,KEIM,SACE,eAAA,EAAA,MAAA,EADF,SACE,eAAA,EAAA,MAAA,EADF,SACE,eAAA,EAAA,MAAA,EADF,SACE,eAAA,EAAA,MAAA,EADF,SACE,eAAA,EAAA,MAAA,EADF,SACE,eAAA,EAAA,MAAA,EADF,SACE,eAAA,EAAA,MAAA,EADF,SACE,eAAA,EAAA,MAAA,EADF,SACE,eAAA,EAAA,MAAA,EADF,UACE,eAAA,GAAA,MAAA,GADF,UACE,eAAA,GAAA,MAAA,GADF,UACE,eAAA,GAAA,MAAA,GDMN,yBCzBE,QACE,wBAAA,EAAA,WAAA,EACA,kBAAA,EAAA,UAAA,EACA,UAAA,KAEF,aACE,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,KACA,UAAA,KAIA,UFFN,SAAA,EAAA,EAAA,UAAA,KAAA,EAAA,EAAA,UAIA,UAAA,UEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,WFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,WFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,WFFN,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KAIA,UAAA,KEIM,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,aACE,eAAA,GAAA,MAAA,GADF,aACE,eAAA,GAAA,MAAA,GADF,aACE,eAAA,GAAA,MAAA,IDMN,yBCzBE,QACE,wBAAA,EAAA,WAAA,EACA,kBAAA,EAAA,UAAA,EACA,UAAA,KAEF,aACE,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,KACA,UAAA,KAIA,UFFN,SAAA,EAAA,EAAA,UAAA,KAAA,EAAA,EAAA,UAIA,UAAA,UEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,WFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,WFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,WFFN,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KAIA,UAAA,KEIM,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,aACE,eAAA,GAAA,MAAA,GADF,aACE,eAAA,GAAA,MAAA,GADF,aACE,eAAA,GAAA,MAAA,IDMN,yBCzBE,QACE,wBAAA,EAAA,WAAA,EACA,kBAAA,EAAA,UAAA,EACA,UAAA,KAEF,aACE,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,KACA,UAAA,KAIA,UFFN,SAAA,EAAA,EAAA,UAAA,KAAA,EAAA,EAAA,UAIA,UAAA,UEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,WFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,WFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,WFFN,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KAIA,UAAA,KEIM,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,aACE,eAAA,GAAA,MAAA,GADF,aACE,eAAA,GAAA,MAAA,GADF,aACE,eAAA,GAAA,MAAA,IDMN,0BCzBE,QACE,wBAAA,EAAA,WAAA,EACA,kBAAA,EAAA,UAAA,EACA,UAAA,KAEF,aACE,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,KACA,UAAA,KAIA,UFFN,SAAA,EAAA,EAAA,UAAA,KAAA,EAAA,EAAA,UAIA,UAAA,UEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,WFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,WFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,WFFN,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KAIA,UAAA,KEIM,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,YACE,eAAA,EAAA,MAAA,EADF,aACE,eAAA,GAAA,MAAA,GADF,aACE,eAAA,GAAA,MAAA,GADF,aACE,eAAA,GAAA,MAAA,IC9CV,OACE,MAAA,KACA,UAAA,KACA,cAAA,KACA,iBAAA,Yf4yCF,UehzCA,UAQI,QAAA,OACA,eAAA,IACA,WAAA,IAAA,MAAA,QAVJ,gBAcI,eAAA,OACA,cAAA,IAAA,MAAA,QAfJ,mBAmBI,WAAA,IAAA,MAAA,QAnBJ,cAuBI,iBAAA,Kf6yCJ,aepyCA,aAGI,QAAA,MASJ,gBACE,OAAA,IAAA,MAAA,QfgyCF,mBejyCA,mBAKI,OAAA,IAAA,MAAA,QfiyCJ,yBetyCA,yBAWM,oBAAA,IAUN,yCAEI,iBAAA,gBASJ,4BAGM,iBAAA,iBC9EJ,ehB+1CF,kBADA,kBgB11CM,iBAAA,QAMJ,kCAKM,iBAAA,QALN,qChB81CF,qCgBr1CU,iBAAA,QAnBR,iBhB82CF,oBADA,oBgBz2CM,iBAAA,QAMJ,oCAKM,iBAAA,QALN,uChB62CF,uCgBp2CU,iBAAA,QAnBR,ehB63CF,kBADA,kBgBx3CM,iBAAA,QAMJ,kCAKM,iBAAA,QALN,qChB43CF,qCgBn3CU,iBAAA,QAnBR,YhB44CF,eADA,egBv4CM,iBAAA,QAMJ,+BAKM,iBAAA,QALN,kChB24CF,kCgBl4CU,iBAAA,QAnBR,ehB25CF,kBADA,kBgBt5CM,iBAAA,QAMJ,kCAKM,iBAAA,QALN,qChB05CF,qCgBj5CU,iBAAA,QAnBR,chB06CF,iBADA,iBgBr6CM,iBAAA,QAMJ,iCAKM,iBAAA,QALN,oChBy6CF,oCgBh6CU,iBAAA,QAnBR,ahBy7CF,gBADA,gBgBp7CM,iBAAA,QAMJ,gCAKM,iBAAA,QALN,mChBw7CF,mCgB/6CU,iBAAA,QAnBR,YhBw8CF,eADA,egBn8CM,iBAAA,QAMJ,+BAKM,iBAAA,QALN,kChBu8CF,kCgB97CU,iBAAA,QAnBR,chBu9CF,iBADA,iBgBl9CM,iBAAA,iBAMJ,iCAKM,iBAAA,iBALN,oChBs9CF,oCgB78CU,iBAAA,iBDiFV,kBAEI,MAAA,KACA,iBAAA,QAIJ,kBAEI,MAAA,QACA,iBAAA,QAIJ,eACE,MAAA,KACA,iBAAA,Qfg4CF,kBel4CA,kBfm4CA,wBe53CI,aAAA,QAPJ,8BAWI,OAAA,EAXJ,uDAgBM,iBAAA,sBAhBN,0CAuBQ,iBAAA,uBFzEJ,yBEsFJ,kBAEI,QAAA,MACA,MAAA,KACA,WAAA,KACA,mBAAA,yBALJ,iCASM,OAAA,GE9JN,cACE,QAAA,MACA,MAAA,KAGA,QAAA,MAAA,OACA,UAAA,KACA,YAAA,KACA,MAAA,QACA,iBAAA,KAEA,iBAAA,KACA,gBAAA,YACA,OAAA,IAAA,MAAA,gBAKE,cAAA,ORnBE,WAAA,aAAA,YAAA,IAAA,CAAA,WAAA,YAAA,KQCN,0BA6BI,iBAAA,YACA,OAAA,ECvBF,oBACE,MAAA,QACA,iBAAA,KACA,aAAA,QACA,QAAA,EDXJ,yCAsCI,MAAA,QAEA,QAAA,EAxCJ,gCAsCI,MAAA,QAEA,QAAA,EAxCJ,oCAsCI,MAAA,QAEA,QAAA,EAxCJ,2BAsCI,MAAA,QAEA,QAAA,EAxCJ,uBAAA,wBAkDI,iBAAA,QAEA,QAAA,EAIJ,gDAEI,OAAA,oBAFJ,qCAWI,MAAA,QACA,iBAAA,KAKJ,mBjBqgDA,oBiBngDE,QAAA,MAUF,gBACE,YAAA,sBACA,eAAA,sBACA,cAAA,EAGF,mBACE,YAAA,sBACA,eAAA,sBACA,UAAA,QAGF,mBACE,YAAA,uBACA,eAAA,uBACA,UAAA,QAUF,iBACE,YAAA,MACA,eAAA,MACA,cAAA,EACA,UAAA,KASF,wBACE,YAAA,MACA,eAAA,MACA,cAAA,EACA,YAAA,KACA,OAAA,MAAA,YACA,aAAA,IAAA,EjBq/CgE,wCiB3/ClE,wCjB2/C2G,qDAC3G,0DACA,6DiB7/CA,qDjB0/CA,0DACA,6DiBj/CI,cAAA,EACA,aAAA,EAaJ,iBAAA,8BjB2+CA,mCACA,sCiB3+CE,QAAA,OAAA,MACA,UAAA,QACA,YAAA,ITxJE,cAAA,MR0oDJ,wEiB9+CA,gEjB6+CA,qEiB7+CA,mDAEI,OAAA,sBAIJ,iBAAA,8BjB6+CA,mCACA,sCiB7+CE,QAAA,MAAA,KACA,UAAA,QACA,YAAA,ITrKE,cAAA,MRypDJ,wEiBh/CA,gEjB++CA,qEiB/+CA,mDAEI,OAAA,sBAUJ,YACE,cAAA,KAGF,WACE,QAAA,MACA,WAAA,OAQF,UACE,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,aAAA,KACA,YAAA,KAJF,ejB6+CA,wBiBr+CI,cAAA,IACA,aAAA,IASJ,YACE,SAAA,SACA,QAAA,MACA,cAAA,MAHF,uCAOM,MAAA,QAKN,kBACE,aAAA,QACA,cAAA,EAGF,kBACE,SAAA,SACA,WAAA,OACA,YAAA,SAHF,6BAMI,SAAA,OAKJ,mBACE,QAAA,aADF,qCAII,eAAA,OAJJ,sCAQI,YAAA,OAYJ,kBACE,QAAA,KACA,WAAA,OACA,UAAA,QACA,MAAA,QAGF,iBACE,SAAA,SACA,IAAA,KACA,QAAA,EACA,QAAA,KACA,MAAA,MACA,QAAA,MACA,WAAA,MACA,UAAA,QACA,YAAA,EACA,MAAA,KACA,iBAAA,mBACA,cAAA,MjB09CF,wBkB3tDI,uBAAA,oCAAA,mCAEE,aAAA,QlB+tDN,8BkBjuDI,6BAAA,0CAAA,yCAKI,WAAA,EAAA,EAAA,EAAA,MAAA,oBlBsuDR,0CACA,yCANuD,yCACvD,wCAA2C,sDAE3C,qDkBzuDI,qDlBsuDJ,oDkB5tDQ,QAAA,MAQJ,6CAAA,yDAGI,MAAA,QAOJ,yDAAA,qEAGI,iBAAA,oBAHJ,2DAAA,uEAMI,MAAA,QAOJ,iDAAA,6DAGI,aAAA,QAHJ,yDAAA,qEAKgB,aAAA,QALhB,kCAAA,8CAQI,WAAA,EAAA,EAAA,EAAA,MAAA,oBlBytDR,0BkB1wDI,yBAAA,sCAAA,qCAEE,aAAA,QlB8wDN,gCkBhxDI,+BAAA,4CAAA,2CAKI,WAAA,EAAA,EAAA,EAAA,MAAA,oBlBqxDR,4CACA,2CANyD,2CACzD,0CAA6C,wDAE7C,uDkBxxDI,uDlBqxDJ,sDkB3wDQ,QAAA,MAQJ,+CAAA,2DAGI,MAAA,QAOJ,2DAAA,uEAGI,iBAAA,oBAHJ,6DAAA,yEAMI,MAAA,QAOJ,mDAAA,+DAGI,aAAA,QAHJ,2DAAA,uEAKgB,aAAA,QALhB,oCAAA,gDAQI,WAAA,EAAA,EAAA,EAAA,MAAA,oBD+NR,aACE,QAAA,YAAA,QAAA,KACA,cAAA,IAAA,KAAA,UAAA,IAAA,KACA,eAAA,OAAA,YAAA,OAHF,yBASI,MAAA,KJ5PA,yBImPJ,mBAeM,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,OAAA,gBAAA,OACA,cAAA,EAlBN,yBAuBM,QAAA,YAAA,QAAA,KACA,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,cAAA,IAAA,KAAA,UAAA,IAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,EA3BN,2BAgCM,QAAA,aACA,MAAA,KACA,eAAA,OAlCN,qCAuCM,QAAA,aAvCN,0BA2CM,MAAA,KA3CN,iCA+CM,cAAA,EACA,eAAA,OAhDN,yBAsDM,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,OAAA,gBAAA,OACA,MAAA,KACA,WAAA,EACA,cAAA,EA3DN,+BA8DM,aAAA,EA9DN,+BAiEM,SAAA,SACA,WAAA,EACA,aAAA,OACA,YAAA,EApEN,6BAyEM,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,OAAA,gBAAA,OACA,aAAA,EA5EN,uCA+EM,SAAA,OACA,QAAA,aACA,aAAA,OACA,eAAA,YAlFN,kDAuFM,IAAA,GE5XN,KACE,QAAA,aACA,YAAA,IACA,WAAA,OACA,YAAA,OACA,eAAA,OACA,oBAAA,KAAA,iBAAA,KAAA,gBAAA,KAAA,YAAA,KACA,OAAA,IAAA,MAAA,YCiEA,QAAA,MAAA,OACA,UAAA,KACA,YAAA,KZ5EE,cAAA,OCCE,WAAA,IAAA,KAAA,YNiBF,WAAA,WgBHA,gBAAA,KAbJ,WAAA,WAiBI,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,IAAA,oBAlBJ,cAAA,cAwBI,QAAA,IAxBJ,YAAA,YA8BI,iBAAA,KAMJ,enBq6DA,yBmBn6DE,eAAA,KASA,aEQE,MAAA,KDtDF,iBAAA,QACA,aAAA,QAGA,mBCkDE,MAAA,KDhDA,iBAAA,QACA,aAAA,QAGF,mBAAA,mBAMI,WAAA,EAAA,EAAA,EAAA,IAAA,mBAKJ,sBAAA,sBAEE,iBAAA,QACA,aAAA,QAGF,oBAAA,oBpBu8DF,mCoBp8DI,iBAAA,QACA,iBAAA,KACA,aAAA,QDcF,eEQE,MAAA,KDtDF,iBAAA,QACA,aAAA,QAGA,qBCkDE,MAAA,KDhDA,iBAAA,QACA,aAAA,QAGF,qBAAA,qBAMI,WAAA,EAAA,EAAA,EAAA,IAAA,qBAKJ,wBAAA,wBAEE,iBAAA,QACA,aAAA,QAGF,sBAAA,sBpBm+DF,qCoBh+DI,iBAAA,QACA,iBAAA,KACA,aAAA,QDcF,aEQE,MAAA,KDtDF,iBAAA,QACA,aAAA,QAGA,mBCkDE,MAAA,KDhDA,iBAAA,QACA,aAAA,QAGF,mBAAA,mBAMI,WAAA,EAAA,EAAA,EAAA,IAAA,mBAKJ,sBAAA,sBAEE,iBAAA,QACA,aAAA,QAGF,oBAAA,oBpB+/DF,mCoB5/DI,iBAAA,QACA,iBAAA,KACA,aAAA,QDcF,UEQE,MAAA,KDtDF,iBAAA,QACA,aAAA,QAGA,gBCkDE,MAAA,KDhDA,iBAAA,QACA,aAAA,QAGF,gBAAA,gBAMI,WAAA,EAAA,EAAA,EAAA,IAAA,oBAKJ,mBAAA,mBAEE,iBAAA,QACA,aAAA,QAGF,iBAAA,iBpB2hEF,gCoBxhEI,iBAAA,QACA,iBAAA,KACA,aAAA,QDcF,aEME,MAAA,KDpDF,iBAAA,QACA,aAAA,QAGA,mBCgDE,MAAA,KD9CA,iBAAA,QACA,aAAA,QAGF,mBAAA,mBAMI,WAAA,EAAA,EAAA,EAAA,IAAA,mBAKJ,sBAAA,sBAEE,iBAAA,QACA,aAAA,QAGF,oBAAA,oBpBujEF,mCoBpjEI,iBAAA,QACA,iBAAA,KACA,aAAA,QDcF,YEQE,MAAA,KDtDF,iBAAA,QACA,aAAA,QAGA,kBCkDE,MAAA,KDhDA,iBAAA,QACA,aAAA,QAGF,kBAAA,kBAMI,WAAA,EAAA,EAAA,EAAA,IAAA,mBAKJ,qBAAA,qBAEE,iBAAA,QACA,aAAA,QAGF,mBAAA,mBpBmlEF,kCoBhlEI,iBAAA,QACA,iBAAA,KACA,aAAA,QDcF,WEME,MAAA,KDpDF,iBAAA,QACA,aAAA,QAGA,iBCgDE,MAAA,KD9CA,iBAAA,QACA,aAAA,QAGF,iBAAA,iBAMI,WAAA,EAAA,EAAA,EAAA,IAAA,qBAKJ,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAGF,kBAAA,kBpB+mEF,iCoB5mEI,iBAAA,QACA,iBAAA,KACA,aAAA,QDcF,UEQE,MAAA,KDtDF,iBAAA,QACA,aAAA,QAGA,gBCkDE,MAAA,KDhDA,iBAAA,QACA,aAAA,QAGF,gBAAA,gBAMI,WAAA,EAAA,EAAA,EAAA,IAAA,kBAKJ,mBAAA,mBAEE,iBAAA,QACA,aAAA,QAGF,iBAAA,iBpB2oEF,gCoBxoEI,iBAAA,QACA,iBAAA,KACA,aAAA,QDoBF,qBCdA,MAAA,QACA,iBAAA,YACA,iBAAA,KACA,aAAA,QjBrCE,2BiBwCA,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,2BAAA,2BAEE,WAAA,EAAA,EAAA,EAAA,IAAA,mBAGF,8BAAA,8BAEE,MAAA,QACA,iBAAA,YAGF,4BAAA,4BpBuoEF,2CoBpoEI,MAAA,KACA,iBAAA,QACA,aAAA,QDbF,uBCdA,MAAA,QACA,iBAAA,YACA,iBAAA,KACA,aAAA,QjBrCE,6BiBwCA,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,6BAAA,6BAEE,WAAA,EAAA,EAAA,EAAA,IAAA,qBAGF,gCAAA,gCAEE,MAAA,QACA,iBAAA,YAGF,8BAAA,8BpBoqEF,6CoBjqEI,MAAA,KACA,iBAAA,QACA,aAAA,QDbF,qBCdA,MAAA,QACA,iBAAA,YACA,iBAAA,KACA,aAAA,QjBrCE,2BiBwCA,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,2BAAA,2BAEE,WAAA,EAAA,EAAA,EAAA,IAAA,mBAGF,8BAAA,8BAEE,MAAA,QACA,iBAAA,YAGF,4BAAA,4BpBisEF,2CoB9rEI,MAAA,KACA,iBAAA,QACA,aAAA,QDbF,kBCdA,MAAA,QACA,iBAAA,YACA,iBAAA,KACA,aAAA,QjBrCE,wBiBwCA,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,wBAAA,wBAEE,WAAA,EAAA,EAAA,EAAA,IAAA,oBAGF,2BAAA,2BAEE,MAAA,QACA,iBAAA,YAGF,yBAAA,yBpB8tEF,wCoB3tEI,MAAA,KACA,iBAAA,QACA,aAAA,QDbF,qBCdA,MAAA,QACA,iBAAA,YACA,iBAAA,KACA,aAAA,QjBrCE,2BiBwCA,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,2BAAA,2BAEE,WAAA,EAAA,EAAA,EAAA,IAAA,mBAGF,8BAAA,8BAEE,MAAA,QACA,iBAAA,YAGF,4BAAA,4BpB2vEF,2CoBxvEI,MAAA,KACA,iBAAA,QACA,aAAA,QDbF,oBCdA,MAAA,QACA,iBAAA,YACA,iBAAA,KACA,aAAA,QjBrCE,0BiBwCA,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,0BAAA,0BAEE,WAAA,EAAA,EAAA,EAAA,IAAA,mBAGF,6BAAA,6BAEE,MAAA,QACA,iBAAA,YAGF,2BAAA,2BpBwxEF,0CoBrxEI,MAAA,KACA,iBAAA,QACA,aAAA,QDbF,mBCdA,MAAA,QACA,iBAAA,YACA,iBAAA,KACA,aAAA,QjBrCE,yBiBwCA,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,yBAAA,yBAEE,WAAA,EAAA,EAAA,EAAA,IAAA,qBAGF,4BAAA,4BAEE,MAAA,QACA,iBAAA,YAGF,0BAAA,0BpBqzEF,yCoBlzEI,MAAA,KACA,iBAAA,QACA,aAAA,QDbF,kBCdA,MAAA,QACA,iBAAA,YACA,iBAAA,KACA,aAAA,QjBrCE,wBiBwCA,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,wBAAA,wBAEE,WAAA,EAAA,EAAA,EAAA,IAAA,kBAGF,2BAAA,2BAEE,MAAA,QACA,iBAAA,YAGF,yBAAA,yBpBk1EF,wCoB/0EI,MAAA,KACA,iBAAA,QACA,aAAA,QDFJ,UACE,YAAA,IACA,MAAA,QACA,cAAA,EAHF,UAAA,iBAAA,iBAAA,mBASI,iBAAA,YATJ,UAAA,iBAAA,gBAeI,aAAA,YhB1EA,gBgB6EA,aAAA,YhBlEA,gBAAA,gBgBqEA,MAAA,QACA,gBAAA,UACA,iBAAA,YAvBJ,mBA0BI,MAAA,QhB1EA,yBAAA,yBgB6EE,gBAAA,KAUN,mBAAA,QC/BE,QAAA,MAAA,KACA,UAAA,QACA,YAAA,IZ5EE,cAAA,MW6GJ,mBAAA,QCnCE,QAAA,OAAA,MACA,UAAA,QACA,YAAA,IZ5EE,cAAA,MWsHJ,WACE,QAAA,MACA,MAAA,KAIF,sBACE,WAAA,MnBm1EF,6BADA,4BmB90EA,6BAII,MAAA,KGzIJ,MACE,QAAA,EbII,WAAA,QAAA,KAAA,OaLN,WAKI,QAAA,EAIJ,UACE,QAAA,KADF,eAGI,QAAA,MAIJ,iBAEI,QAAA,UAIJ,oBAEI,QAAA,gBAIJ,YACE,SAAA,SACA,OAAA,EACA,SAAA,Ob1BI,WAAA,OAAA,KAAA,KTo/EN,UuBx/EA,QAEE,SAAA,SAGF,wBAGI,QAAA,aACA,MAAA,EACA,OAAA,EACA,YAAA,OACA,eAAA,OACA,QAAA,GACA,WAAA,KAAA,MACA,aAAA,KAAA,MAAA,YACA,YAAA,KAAA,MAAA,YAXJ,8BAeI,YAAA,EAMJ,gCAGM,WAAA,EACA,cAAA,KAAA,MAMN,eACE,SAAA,SACA,IAAA,KACA,KAAA,EACA,QAAA,KACA,QAAA,KACA,MAAA,KACA,UAAA,MACA,QAAA,MAAA,EACA,OAAA,QAAA,EAAA,EACA,UAAA,KACA,MAAA,QACA,WAAA,KACA,WAAA,KACA,iBAAA,KACA,gBAAA,YACA,OAAA,IAAA,MAAA,gBfjDE,cAAA,OeuDJ,kBCtDE,OAAA,EACA,OAAA,MAAA,EACA,SAAA,OACA,WAAA,IAAA,MAAA,QD0DF,eACE,QAAA,MACA,MAAA,KACA,QAAA,OAAA,OACA,MAAA,KACA,YAAA,IACA,MAAA,QACA,WAAA,QACA,YAAA,OACA,WAAA,IACA,OAAA,EpBtDE,qBAAA,qBoByDA,MAAA,QACA,gBAAA,KACA,iBAAA,QAfJ,sBAAA,sBAoBI,MAAA,KACA,gBAAA,KACA,iBAAA,QAtBJ,wBAAA,wBA2BI,MAAA,QACA,iBAAA,YASJ,QAGI,QAAA,EAIJ,oBACE,QAAA,MAIF,iBACE,QAAA,MACA,QAAA,MAAA,OACA,cAAA,EACA,UAAA,QACA,MAAA,QACA,YAAA,OEtHF,WzB0lFA,oByBxlFE,SAAA,SACA,QAAA,mBAAA,QAAA,YACA,eAAA,OzB8lFF,yByBlmFA,gBAOI,SAAA,SACA,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,cAAA,EzBimFJ,+ByB1mFA,sBAcM,QAAA,EzBmmFN,gCADA,gCADA,+ByB/mFA,uBAAA,uBAAA,sBAmBM,QAAA,EAnBN,qBzBsnFA,2BACA,2BACA,iCACA,8BACA,oCACA,oCACA,0CyBhmFI,YAAA,KAKJ,aACE,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,cAAA,MAAA,gBAAA,WAHF,0BAMI,MAAA,KAIJ,yEACE,cAAA,EAIF,4BACE,YAAA,EADF,mEjBlCI,wBAAA,EACA,2BAAA,EiByCJ,6CzBmmFA,8CQ/nFI,uBAAA,EACA,0BAAA,EiBiCJ,sBACE,MAAA,KAEF,8DACE,cAAA,EAEF,mEzBqmFA,oEQ3pFI,wBAAA,EACA,2BAAA,EiB2DJ,oEjB9CI,uBAAA,EACA,0BAAA,EiB8DJ,4BACE,cAAA,SACA,aAAA,SAFF,mCAKI,YAAA,EAIJ,0CAAA,+BACE,cAAA,QACA,aAAA,QAGF,0CAAA,+BACE,cAAA,OACA,aAAA,OAoBF,oBACE,QAAA,mBAAA,QAAA,YACA,mBAAA,OAAA,eAAA,OACA,eAAA,MAAA,YAAA,WACA,cAAA,OAAA,gBAAA,OAJF,yBzBmlFA,+ByB3kFI,MAAA,KARJ,8BzBwlFA,oCACA,oCACA,0CyB3kFI,WAAA,KACA,YAAA,EAIJ,4DAEI,cAAA,EAFJ,sDjB9HI,2BAAA,EACA,0BAAA,EiB6HJ,sDjB5II,uBAAA,EACA,wBAAA,EiBsJJ,uEACE,cAAA,EAEF,4EzBglFA,6EQ5tFI,2BAAA,EACA,0BAAA,EiBiJJ,6EjBhKI,uBAAA,EACA,wBAAA,ERovFJ,gDExLA,6CF0LA,2DADA,wDyBhkFM,SAAA,SACA,KAAA,cACA,eAAA,KC9LN,aACE,SAAA,SACA,QAAA,YAAA,QAAA,KACA,MAAA,KAHF,2BAQI,SAAA,SACA,QAAA,EACA,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KAGA,MAAA,GACA,cAAA,EAdJ,kCAAA,iCAAA,iCAkBM,QAAA,E1BuwFN,2B0BlwFA,mB1BiwFA,iB0B7vFE,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,O1BswFF,8D0B3wFA,sD1B0wFA,oDQjyFI,cAAA,EkBmCJ,mB1BowFA,iB0BlwFE,YAAA,OACA,eAAA,OAyBF,mBACE,QAAA,MAAA,OACA,cAAA,EACA,UAAA,KACA,YAAA,IACA,YAAA,KACA,MAAA,QACA,WAAA,OACA,iBAAA,QACA,OAAA,IAAA,MAAA,gBlBxEE,cAAA,OkB+DJ,mC1B2vFA,mCACA,wD0B9uFI,QAAA,OAAA,MACA,UAAA,QlB9EA,cAAA,MkB+DJ,mC1BmwFA,mCACA,wD0BhvFI,QAAA,MAAA,KACA,UAAA,QlBpFA,cAAA,MR00FJ,wC0B3wFA,qCA6BI,WAAA,EAUJ,4C1ByuFA,oCAKA,oEADA,+EAHA,uCACA,kDACA,mDQr0FI,wBAAA,EACA,2BAAA,EkBiGJ,oCACE,aAAA,EAEF,6C1B4uFA,qCACA,wCACA,mDACA,oDAEA,oEADA,yDQv0FI,uBAAA,EACA,0BAAA,EkB+FJ,mDACE,YAAA,EAOF,iBACE,SAAA,SAGA,UAAA,EACA,YAAA,OALF,sBAUI,SAAA,SAVJ,2BAaM,YAAA,KAbN,6BAAA,4BAAA,4BAkBM,QAAA,EAlBN,uC1B4vFA,6C0BluFM,aAAA,KA1BN,wC1BiwFA,8C0BjuFM,QAAA,EACA,YAAA,K1BuuFN,qDADA,oDAEA,oD0BzwFA,+CAAA,8CAAA,8CAoCQ,QAAA,EChKR,gBACE,SAAA,SACA,QAAA,mBAAA,QAAA,YACA,WAAA,OACA,aAAA,OACA,aAAA,KAGF,sBACE,SAAA,SACA,QAAA,GACA,QAAA,EAHF,wDAMI,MAAA,KACA,iBAAA,QAPJ,sDAaI,WAAA,EAAA,EAAA,EAAA,IAAA,IAAA,CAAA,EAAA,EAAA,EAAA,IAAA,QAbJ,uDAiBI,MAAA,KACA,iBAAA,QAlBJ,yDAwBM,iBAAA,QAxBN,2DA4BM,MAAA,QASN,0BACE,SAAA,SACA,IAAA,OACA,KAAA,EACA,QAAA,MACA,MAAA,KACA,OAAA,KACA,eAAA,KACA,oBAAA,KAAA,iBAAA,KAAA,gBAAA,KAAA,YAAA,KACA,iBAAA,KACA,kBAAA,UACA,oBAAA,OAAA,OACA,gBAAA,IAAA,IAQF,2CnBxEI,cAAA,OmBwEJ,yEAMI,iBAAA,yMANJ,+EAUI,iBAAA,QACA,iBAAA,sJASJ,wCAEI,cAAA,IAFJ,sEAMI,iBAAA,mJAUJ,yBACE,QAAA,YAAA,QAAA,KACA,mBAAA,OAAA,eAAA,OAFF,yCAKI,cAAA,OALJ,yDAQM,YAAA,EAYN,eACE,QAAA,aACA,UAAA,KACA,OAAA,oBACA,QAAA,QAAA,QAAA,QAAA,OACA,YAAA,KACA,MAAA,QACA,eAAA,OACA,WAAA,KAAA,oKAAA,UAAA,MAAA,OAAA,OACA,gBAAA,IAAA,KACA,OAAA,IAAA,MAAA,gBAEE,cAAA,OAIF,mBAAA,KAAA,gBAAA,KAAA,WAAA,KAhBF,qBAmBI,aAAA,QACA,QAAA,EApBJ,gCA6BM,MAAA,QACA,iBAAA,KA9BN,wBAmCI,MAAA,QACA,iBAAA,QApCJ,2BAyCI,QAAA,EAIJ,kBACE,OAAA,sBACA,YAAA,QACA,eAAA,QACA,UAAA,IAQF,aACE,SAAA,SACA,QAAA,aACA,UAAA,KACA,OAAA,OACA,cAAA,EAGF,mBACE,UAAA,MACA,UAAA,KACA,OAAA,OACA,OAAA,EACA,QAAA,EAOF,qBACE,SAAA,SACA,IAAA,EACA,MAAA,EACA,KAAA,EACA,QAAA,EACA,OAAA,OACA,QAAA,MAAA,KACA,YAAA,IACA,MAAA,QACA,eAAA,KACA,oBAAA,KAAA,iBAAA,KAAA,gBAAA,KAAA,YAAA,KACA,iBAAA,KACA,OAAA,IAAA,MAAA,gBnB1NE,cAAA,OmB6MJ,2CAmBM,QAAA,iBAnBN,6BAwBI,SAAA,SACA,IAAA,KACA,MAAA,KACA,OAAA,KACA,QAAA,EACA,QAAA,MACA,OAAA,OACA,QAAA,MAAA,KACA,YAAA,IACA,MAAA,QACA,iBAAA,QACA,OAAA,IAAA,MAAA,gBnBhPA,cAAA,EAAA,OAAA,OAAA,EmB6MJ,sCAyCM,QAAA,SCrPN,KACE,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,aAAA,EACA,cAAA,EACA,WAAA,KAGF,UACE,QAAA,MACA,QAAA,MAAA,KzBOE,gBAAA,gByBJA,gBAAA,KALJ,mBAUI,MAAA,QAQJ,UACE,cAAA,IAAA,MAAA,KADF,oBAII,cAAA,KAJJ,oBAQI,OAAA,IAAA,MAAA,YpB7BA,uBAAA,OACA,wBAAA,OoBoBJ,0BAAA,0BAYM,aAAA,QAAA,QAAA,KAZN,6BAgBM,MAAA,QACA,iBAAA,YACA,aAAA,Y5BqlGN,mC4BvmGA,2BAwBI,MAAA,QACA,iBAAA,KACA,aAAA,KAAA,KAAA,KA1BJ,yBA+BI,WAAA,KpBpDA,uBAAA,EACA,wBAAA,EoB8DJ,qBpBrEI,cAAA,OoBqEJ,4B5B8kGA,2B4BxkGM,MAAA,KACA,iBAAA,QAUN,oBAEI,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,WAAA,OAIJ,yBAEI,wBAAA,EAAA,WAAA,EACA,kBAAA,EAAA,UAAA,EACA,WAAA,OASJ,uBAEI,QAAA,KAFJ,qBAKI,QAAA,MClGJ,QACE,SAAA,SACA,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,QAAA,gBAAA,cACA,QAAA,MAAA,KANF,mB7B+qGA,yB6BnqGI,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,QAAA,gBAAA,chBqCA,yBgBpDJ,mB7B4rGE,yB6B1qGI,MAAA,KACA,aAAA,EACA,YAAA,GAUN,cACE,QAAA,aACA,YAAA,SACA,eAAA,SACA,aAAA,KACA,UAAA,QACA,YAAA,QACA,YAAA,O1BhCE,oBAAA,oB0BmCA,gBAAA,KASJ,YACE,QAAA,YAAA,QAAA,KACA,mBAAA,OAAA,eAAA,OACA,aAAA,EACA,cAAA,EACA,WAAA,KALF,sBAQI,cAAA,EACA,aAAA,EATJ,2BAaI,SAAA,OACA,MAAA,KASJ,aACE,QAAA,aACA,YAAA,MACA,eAAA,MAYF,iBACE,wBAAA,KAAA,WAAA,KAIF,gBACE,QAAA,OAAA,OACA,UAAA,QACA,YAAA,EACA,WAAA,IACA,OAAA,IAAA,MAAA,YrB9GE,cAAA,OLkBA,sBAAA,sB0BgGA,gBAAA,KAMJ,qBACE,QAAA,aACA,MAAA,MACA,OAAA,MACA,eAAA,OACA,QAAA,GACA,WAAA,UAAA,OAAA,OACA,gBAAA,KAAA,KhB9DE,yBgBwEA,6B7B6oGF,mC6BzoGQ,cAAA,EACA,aAAA,GhB1FN,yBgBqFA,kBAUI,mBAAA,IAAA,eAAA,IACA,cAAA,OAAA,UAAA,OACA,cAAA,MAAA,gBAAA,WAZJ,8BAeM,mBAAA,IAAA,eAAA,IAfN,6CAkBQ,SAAA,SAlBR,mDAsBQ,MAAA,EACA,KAAA,KAvBR,wCA2BQ,cAAA,MACA,aAAA,MA5BR,6B7B4qGF,mC6BzoGQ,cAAA,OAAA,UAAA,OAnCN,mCAwCM,QAAA,sBAAA,QAAA,eAxCN,kCA6CM,QAAA,MhBrHN,yBgBwEA,6B7B2rGF,mC6BvrGQ,cAAA,EACA,aAAA,GhB1FN,yBgBqFA,kBAUI,mBAAA,IAAA,eAAA,IACA,cAAA,OAAA,UAAA,OACA,cAAA,MAAA,gBAAA,WAZJ,8BAeM,mBAAA,IAAA,eAAA,IAfN,6CAkBQ,SAAA,SAlBR,mDAsBQ,MAAA,EACA,KAAA,KAvBR,wCA2BQ,cAAA,MACA,aAAA,MA5BR,6B7B0tGF,mC6BvrGQ,cAAA,OAAA,UAAA,OAnCN,mCAwCM,QAAA,sBAAA,QAAA,eAxCN,kCA6CM,QAAA,MhBrHN,yBgBwEA,6B7ByuGF,mC6BruGQ,cAAA,EACA,aAAA,GhB1FN,yBgBqFA,kBAUI,mBAAA,IAAA,eAAA,IACA,cAAA,OAAA,UAAA,OACA,cAAA,MAAA,gBAAA,WAZJ,8BAeM,mBAAA,IAAA,eAAA,IAfN,6CAkBQ,SAAA,SAlBR,mDAsBQ,MAAA,EACA,KAAA,KAvBR,wCA2BQ,cAAA,MACA,aAAA,MA5BR,6B7BwwGF,mC6BruGQ,cAAA,OAAA,UAAA,OAnCN,mCAwCM,QAAA,sBAAA,QAAA,eAxCN,kCA6CM,QAAA,MhBrHN,0BgBwEA,6B7BuxGF,mC6BnxGQ,cAAA,EACA,aAAA,GhB1FN,0BgBqFA,kBAUI,mBAAA,IAAA,eAAA,IACA,cAAA,OAAA,UAAA,OACA,cAAA,MAAA,gBAAA,WAZJ,8BAeM,mBAAA,IAAA,eAAA,IAfN,6CAkBQ,SAAA,SAlBR,mDAsBQ,MAAA,EACA,KAAA,KAvBR,wCA2BQ,cAAA,MACA,aAAA,MA5BR,6B7BszGF,mC6BnxGQ,cAAA,OAAA,UAAA,OAnCN,mCAwCM,QAAA,sBAAA,QAAA,eAxCN,kCA6CM,QAAA,MAlDV,eAeQ,mBAAA,IAAA,eAAA,IACA,cAAA,OAAA,UAAA,OACA,cAAA,MAAA,gBAAA,WAjBR,0B7Bk1GA,gC6Bz0GU,cAAA,EACA,aAAA,EAVV,2BAoBU,mBAAA,IAAA,eAAA,IApBV,0CAuBY,SAAA,SAvBZ,gDA2BY,MAAA,EACA,KAAA,KA5BZ,qCAgCY,cAAA,MACA,aAAA,MAjCZ,0B7B22GA,gC6Bn0GU,cAAA,OAAA,UAAA,OAxCV,gCA6CU,QAAA,sBAAA,QAAA,eA7CV,+BAkDU,QAAA,KAaV,4BAEI,MAAA,eAFJ,kCAAA,kCAKM,MAAA,eALN,oCAWM,MAAA,eAXN,0CAAA,0CAcQ,MAAA,eAdR,6CAkBQ,MAAA,e7B6zGR,4CAEA,2CADA,yC6Bh1GA,0CA0BM,MAAA,eA1BN,8BA+BI,MAAA,eACA,aAAA,eAhCJ,mCAoCI,iBAAA,oPApCJ,2BAwCI,MAAA,eAKJ,2BAEI,MAAA,KAFJ,iCAAA,iCAKM,MAAA,KALN,mCAWM,MAAA,qBAXN,yCAAA,yCAcQ,MAAA,sBAdR,4CAkBQ,MAAA,sB7BwzGR,2CAEA,0CADA,wC6B30GA,yCA0BM,MAAA,KA1BN,6BA+BI,MAAA,qBACA,aAAA,qBAhCJ,kCAoCI,iBAAA,0PApCJ,0BAwCI,MAAA,qBCxRJ,MACE,SAAA,SACA,QAAA,YAAA,QAAA,KACA,mBAAA,OAAA,eAAA,OACA,UAAA,EACA,UAAA,WACA,iBAAA,KACA,gBAAA,WACA,OAAA,IAAA,MAAA,iBtBRE,cAAA,OsBYJ,WAGE,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,QAAA,QAGF,YACE,cAAA,OAGF,eACE,WAAA,SACA,cAAA,EAGF,sBACE,cAAA,E3BtBE,iB2B2BA,gBAAA,KAFJ,sBAMI,YAAA,QAIJ,2DtBpCI,uBAAA,OACA,wBAAA,OsBmCJ,yDtBtBI,2BAAA,OACA,0BAAA,OsBwCJ,aACE,QAAA,OAAA,QACA,cAAA,EACA,iBAAA,gBACA,cAAA,IAAA,MAAA,iBAJF,yBtB7DI,cAAA,mBAAA,mBAAA,EAAA,EsBwEJ,aACE,QAAA,OAAA,QACA,iBAAA,gBACA,WAAA,IAAA,MAAA,iBAHF,wBtBxEI,cAAA,EAAA,EAAA,mBAAA,mBsBuFJ,kBACE,aAAA,SACA,cAAA,QACA,YAAA,SACA,cAAA,EAGF,mBACE,aAAA,SACA,YAAA,SAIF,kBACE,SAAA,SACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,QAGF,UACE,MAAA,KtB9GE,cAAA,mBsBmHJ,cACE,MAAA,KtB9GE,uBAAA,mBACA,wBAAA,mBsBiHJ,iBACE,MAAA,KtBrGE,2BAAA,mBACA,0BAAA,mBK+BA,yBiB6EF,WACE,QAAA,YAAA,QAAA,KACA,cAAA,IAAA,KAAA,UAAA,IAAA,KACA,aAAA,MACA,YAAA,MAJF,iBAOI,QAAA,YAAA,QAAA,KACA,SAAA,EAAA,EAAA,GAAA,KAAA,EAAA,EAAA,GACA,mBAAA,OAAA,eAAA,OACA,aAAA,KACA,YAAA,MjBxFF,yBiBmGF,YACE,QAAA,YAAA,QAAA,KACA,cAAA,IAAA,KAAA,UAAA,IAAA,KAFF,kBAKI,SAAA,EAAA,EAAA,GAAA,KAAA,EAAA,EAAA,GALJ,wBAQM,YAAA,EACA,YAAA,EATN,8BtB1IE,wBAAA,EACA,2BAAA,EsByIF,4CAkBU,wBAAA,EAlBV,+CAqBU,2BAAA,EArBV,6BtB5HE,uBAAA,EACA,0BAAA,EsB2HF,2CA4BU,uBAAA,EA5BV,8CA+BU,0BAAA,EA/BV,qDAoCQ,cAAA,E9B4jHR,sE8BhmHA,mEAwCU,cAAA,GAaZ,oBAEI,cAAA,OjB1JA,yBiBwJJ,cAMI,qBAAA,EAAA,kBAAA,EAAA,aAAA,EACA,mBAAA,QAAA,gBAAA,QAAA,WAAA,QAPJ,oBAUM,QAAA,aACA,MAAA,MC3NN,YACE,QAAA,OAAA,KACA,cAAA,KACA,WAAA,KACA,iBAAA,QvBAE,cAAA,OwBHF,mBACE,QAAA,MACA,MAAA,KACA,QAAA,GDKJ,iBACE,MAAA,KADF,0CAKI,QAAA,aACA,cAAA,MACA,aAAA,MACA,MAAA,QACA,QAAA,IATJ,gDAmBI,gBAAA,UAnBJ,gDAsBI,gBAAA,KAtBJ,wBA0BI,MAAA,QEnCJ,YACE,QAAA,YAAA,QAAA,KAEA,aAAA,EACA,WAAA,KzBAE,cAAA,OyBIJ,kCAGM,YAAA,EzBoBF,uBAAA,OACA,0BAAA,OyBxBJ,iCzBSI,wBAAA,OACA,2BAAA,OyBVJ,6BAcI,QAAA,EACA,MAAA,KACA,iBAAA,QACA,aAAA,QAjBJ,+BAqBI,MAAA,QACA,eAAA,KACA,iBAAA,KACA,aAAA,KAIJ,WACE,SAAA,SACA,QAAA,MACA,QAAA,MAAA,OACA,YAAA,KACA,YAAA,KACA,MAAA,QACA,iBAAA,KACA,OAAA,IAAA,MAAA,K9BtBE,iBAAA,iB8ByBA,MAAA,QACA,gBAAA,KACA,iBAAA,QACA,aAAA,KC/CF,0BACE,QAAA,OAAA,OACA,UAAA,QACA,YAAA,IAKE,iD1BoBF,uBAAA,MACA,0BAAA,M0BhBE,gD1BCF,wBAAA,MACA,2BAAA,M0BfF,0BACE,QAAA,OAAA,MACA,UAAA,QACA,YAAA,IAKE,iD1BoBF,uBAAA,MACA,0BAAA,M0BhBE,gD1BCF,wBAAA,MACA,2BAAA,M2BbJ,OACE,QAAA,aACA,QAAA,MAAA,KACA,UAAA,IACA,YAAA,IACA,YAAA,EACA,MAAA,KACA,WAAA,OACA,YAAA,OACA,eAAA,S3BVE,cAAA,O2BCJ,aAcI,QAAA,KAKJ,YACE,SAAA,SACA,IAAA,KAOF,YACE,cAAA,KACA,aAAA,K3B/BE,cAAA,M2BwCF,ediBE,MAAA,Ke3DF,iBAAA,QjCoBE,2BAAA,2BkBuCA,MAAA,KetDE,gBAAA,KACA,iBAAA,QDoCJ,iBdiBE,MAAA,Ke3DF,iBAAA,QjCoBE,6BAAA,6BkBuCA,MAAA,KetDE,gBAAA,KACA,iBAAA,QDoCJ,ediBE,MAAA,Ke3DF,iBAAA,QjCoBE,2BAAA,2BkBuCA,MAAA,KetDE,gBAAA,KACA,iBAAA,QDoCJ,YdiBE,MAAA,Ke3DF,iBAAA,QjCoBE,wBAAA,wBkBuCA,MAAA,KetDE,gBAAA,KACA,iBAAA,QDoCJ,edeE,MAAA,KezDF,iBAAA,QjCoBE,2BAAA,2BkBqCA,MAAA,KepDE,gBAAA,KACA,iBAAA,QDoCJ,cdiBE,MAAA,Ke3DF,iBAAA,QjCoBE,0BAAA,0BkBuCA,MAAA,KetDE,gBAAA,KACA,iBAAA,QDoCJ,adeE,MAAA,KezDF,iBAAA,QjCoBE,yBAAA,yBkBqCA,MAAA,KepDE,gBAAA,KACA,iBAAA,QDoCJ,YdiBE,MAAA,Ke3DF,iBAAA,QjCoBE,wBAAA,wBkBuCA,MAAA,KetDE,gBAAA,KACA,iBAAA,QCRN,WACE,QAAA,KAAA,KACA,cAAA,KACA,iBAAA,Q7BCE,cAAA,MKoDA,yBwBxDJ,WAOI,QAAA,KAAA,MAIJ,iBACE,cAAA,EACA,aAAA,E7BTE,cAAA,E8BAJ,OACE,QAAA,OAAA,QACA,cAAA,KACA,OAAA,IAAA,MAAA,Y9BHE,cAAA,O8BQJ,eAEE,MAAA,QAIF,YACE,YAAA,IAQF,0BAGI,SAAA,SACA,IAAA,QACA,MAAA,SACA,QAAA,OAAA,QACA,MAAA,QAUF,eC3CA,MAAA,QACA,iBAAA,QACA,aAAA,QAEA,kBACE,iBAAA,QAGF,2BACE,MAAA,QDkCF,iBC3CA,MAAA,QACA,iBAAA,QACA,aAAA,QAEA,oBACE,iBAAA,QAGF,6BACE,MAAA,QDkCF,eC3CA,MAAA,QACA,iBAAA,QACA,aAAA,QAEA,kBACE,iBAAA,QAGF,2BACE,MAAA,QDkCF,YC3CA,MAAA,QACA,iBAAA,QACA,aAAA,QAEA,eACE,iBAAA,QAGF,wBACE,MAAA,QDkCF,eC3CA,MAAA,QACA,iBAAA,QACA,aAAA,QAEA,kBACE,iBAAA,QAGF,2BACE,MAAA,QDkCF,cC3CA,MAAA,QACA,iBAAA,QACA,aAAA,QAEA,iBACE,iBAAA,QAGF,0BACE,MAAA,QDkCF,aC3CA,MAAA,QACA,iBAAA,QACA,aAAA,QAEA,gBACE,iBAAA,QAGF,yBACE,MAAA,QDkCF,YC3CA,MAAA,QACA,iBAAA,QACA,aAAA,QAEA,eACE,iBAAA,QAGF,wBACE,MAAA,QCVJ,wCACE,KAAO,oBAAA,KAAA,EACP,GAAK,oBAAA,EAAA,GAFP,gCACE,KAAO,oBAAA,KAAA,EACP,GAAK,oBAAA,EAAA,GAGP,UACE,QAAA,YAAA,QAAA,KACA,SAAA,OACA,UAAA,OACA,YAAA,KACA,WAAA,OACA,iBAAA,QhCPE,cAAA,OgCYJ,cACE,OAAA,KACA,YAAA,KACA,MAAA,KACA,iBAAA,Q/BfI,WAAA,MAAA,IAAA,K+BmBN,sBCWE,iBAAA,iKDTA,gBAAA,KAAA,KAGF,uBACE,kBAAA,qBAAA,GAAA,OAAA,SAAA,UAAA,qBAAA,GAAA,OAAA,SE9BF,OACE,QAAA,YAAA,QAAA,KACA,eAAA,MAAA,YAAA,WAGF,YACE,SAAA,EAAA,KAAA,ECFF,YACE,QAAA,YAAA,QAAA,KACA,mBAAA,OAAA,eAAA,OAGA,aAAA,EACA,cAAA,EASF,wBACE,MAAA,KACA,MAAA,QACA,WAAA,QxCAE,8BAAA,8BwCIA,MAAA,QACA,gBAAA,KACA,iBAAA,QATJ,+BAaI,MAAA,QACA,iBAAA,QASJ,iBACE,SAAA,SACA,QAAA,MACA,QAAA,OAAA,QAEA,cAAA,KACA,iBAAA,KACA,OAAA,IAAA,MAAA,iBAPF,6BnChCI,uBAAA,OACA,wBAAA,OmC+BJ,4BAcI,cAAA,EnChCA,2BAAA,OACA,0BAAA,OLHA,uBAAA,uBwCuCA,gBAAA,KAnBJ,0BAAA,0BAwBI,MAAA,QACA,iBAAA,KAzBJ,wBA8BI,QAAA,EACA,MAAA,KACA,iBAAA,QACA,aAAA,QAUJ,mCAEI,aAAA,EACA,YAAA,EACA,cAAA,EAJJ,2DASM,WAAA,EATN,yDAeM,cAAA,ECjGJ,yBACE,MAAA,QACA,iBAAA,QAIF,0B5C8xIF,+B4C5xII,MAAA,QzCWA,gCAAA,gCHsxIJ,qCACA,qC4C/xIM,MAAA,QACA,iBAAA,QANJ,iC5C0yIF,sC4ChyIM,MAAA,KACA,iBAAA,QACA,aAAA,QAlBJ,2BACE,MAAA,QACA,iBAAA,QAIF,4B5CszIF,iC4CpzII,MAAA,QzCWA,kCAAA,kCH8yIJ,uCACA,uC4CvzIM,MAAA,QACA,iBAAA,QANJ,mC5Ck0IF,wC4CxzIM,MAAA,KACA,iBAAA,QACA,aAAA,QAlBJ,yBACE,MAAA,QACA,iBAAA,QAIF,0B5C80IF,+B4C50II,MAAA,QzCWA,gCAAA,gCHs0IJ,qCACA,qC4C/0IM,MAAA,QACA,iBAAA,QANJ,iC5C01IF,sC4Ch1IM,MAAA,KACA,iBAAA,QACA,aAAA,QAlBJ,sBACE,MAAA,QACA,iBAAA,QAIF,uB5Cs2IF,4B4Cp2II,MAAA,QzCWA,6BAAA,6BH81IJ,kCACA,kC4Cv2IM,MAAA,QACA,iBAAA,QANJ,8B5Ck3IF,mC4Cx2IM,MAAA,KACA,iBAAA,QACA,aAAA,QAlBJ,yBACE,MAAA,QACA,iBAAA,QAIF,0B5C83IF,+B4C53II,MAAA,QzCWA,gCAAA,gCHs3IJ,qCACA,qC4C/3IM,MAAA,QACA,iBAAA,QANJ,iC5C04IF,sC4Ch4IM,MAAA,KACA,iBAAA,QACA,aAAA,QAlBJ,wBACE,MAAA,QACA,iBAAA,QAIF,yB5Cs5IF,8B4Cp5II,MAAA,QzCWA,+BAAA,+BH84IJ,oCACA,oC4Cv5IM,MAAA,QACA,iBAAA,QANJ,gC5Ck6IF,qC4Cx5IM,MAAA,KACA,iBAAA,QACA,aAAA,QAlBJ,uBACE,MAAA,QACA,iBAAA,QAIF,wB5C86IF,6B4C56II,MAAA,QzCWA,8BAAA,8BHs6IJ,mCACA,mC4C/6IM,MAAA,QACA,iBAAA,QANJ,+B5C07IF,oC4Ch7IM,MAAA,KACA,iBAAA,QACA,aAAA,QAlBJ,sBACE,MAAA,QACA,iBAAA,QAIF,uB5Cs8IF,4B4Cp8II,MAAA,QzCWA,6BAAA,6BH87IJ,kCACA,kC4Cv8IM,MAAA,QACA,iBAAA,QANJ,8B5Ck9IF,mC4Cx8IM,MAAA,KACA,iBAAA,QACA,aAAA,QCrBN,OACE,MAAA,MACA,UAAA,OACA,YAAA,IACA,YAAA,EACA,MAAA,KACA,YAAA,EAAA,IAAA,EAAA,KACA,QAAA,G1CeE,aAAA,a0CZA,MAAA,KACA,gBAAA,KACA,QAAA,IAUJ,aACE,QAAA,EACA,WAAA,IACA,OAAA,EACA,mBAAA,KCnBF,YACE,SAAA,OAIF,OACE,SAAA,MACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,KACA,QAAA,KACA,SAAA,OAGA,QAAA,EAXF,0BrCPM,WAAA,kBAAA,IAAA,SAAA,WAAA,UAAA,IAAA,SAAA,WAAA,UAAA,IAAA,QAAA,CAAA,kBAAA,IAAA,SqC0BF,kBAAA,kBAAA,UAAA,kBAnBJ,0BAqByB,kBAAA,eAAA,UAAA,eAEzB,mBACE,WAAA,OACA,WAAA,KAIF,cACE,SAAA,SACA,MAAA,KACA,OAAA,KAIF,eACE,SAAA,SACA,QAAA,YAAA,QAAA,KACA,mBAAA,OAAA,eAAA,OACA,iBAAA,KACA,gBAAA,YACA,OAAA,IAAA,MAAA,etClDE,cAAA,MsCsDF,QAAA,EAIF,gBACE,SAAA,MACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,KACA,iBAAA,KAPF,qBAUW,QAAA,EAVX,qBAWW,QAAA,GAKX,cACE,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,QAAA,gBAAA,cACA,QAAA,KACA,cAAA,IAAA,MAAA,QAIF,aACE,cAAA,EACA,YAAA,IAKF,YACE,SAAA,SAGA,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,QAAA,KAIF,cACE,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,IAAA,gBAAA,SACA,QAAA,KACA,WAAA,IAAA,MAAA,QALF,iCAQyB,YAAA,OARzB,gCASwB,aAAA,OAIxB,yBACE,SAAA,SACA,IAAA,QACA,MAAA,KACA,OAAA,KACA,SAAA,OjCjEE,yBiCuEF,cACE,UAAA,MACA,OAAA,KAAA,KAOF,UAAY,UAAA,OjChFV,yBiCoFF,UAAY,UAAA,OC3Id,SACE,SAAA,SACA,QAAA,KACA,QAAA,MACA,OAAA,ECHA,YAAA,aAAA,CAAA,kBAAA,CAAA,UAAA,CAAA,MAAA,CAAA,gBAAA,CAAA,KAAA,CAAA,WAEA,WAAA,OACA,YAAA,IACA,YAAA,IACA,WAAA,KACA,WAAA,MACA,gBAAA,KACA,YAAA,KACA,eAAA,KACA,eAAA,OACA,WAAA,OACA,aAAA,OACA,YAAA,OACA,WAAA,KDPA,UAAA,QAEA,UAAA,WACA,QAAA,EAXF,cAaW,QAAA,GAbX,gBAgBI,SAAA,SACA,QAAA,MACA,MAAA,IACA,OAAA,IAnBJ,2CAAA,wBAuBI,QAAA,IAAA,EAvBJ,kDAAA,+BAyBM,OAAA,EAzBN,0DAAA,uCA6BM,YAAA,KACA,QAAA,GACA,aAAA,IAAA,IAAA,EACA,iBAAA,KAhCN,6CAAA,0BAoCI,QAAA,EAAA,IApCJ,oDAAA,iCAsCM,KAAA,EAtCN,4DAAA,yCA0CM,WAAA,KACA,QAAA,GACA,aAAA,IAAA,IAAA,IAAA,EACA,mBAAA,KA7CN,8CAAA,2BAiDI,QAAA,IAAA,EAjDJ,qDAAA,kCAmDM,IAAA,EAnDN,6DAAA,0CAuDM,YAAA,KACA,QAAA,GACA,aAAA,EAAA,IAAA,IACA,oBAAA,KA1DN,4CAAA,yBA8DI,QAAA,EAAA,IA9DJ,mDAAA,gCAgEM,MAAA,EAhEN,2DAAA,wCAoEM,MAAA,EACA,WAAA,KACA,QAAA,GACA,aAAA,IAAA,EAAA,IAAA,IACA,kBAAA,KAxEN,wBA2FI,SAAA,SACA,aAAA,YACA,aAAA,MAKJ,eACE,UAAA,MACA,QAAA,IAAA,IACA,MAAA,KACA,WAAA,OACA,iBAAA,KvCpGE,cAAA,OyCJJ,SACE,SAAA,SACA,IAAA,EACA,KAAA,EACA,QAAA,KACA,QAAA,MACA,UAAA,MACA,QAAA,IDLA,YAAA,aAAA,CAAA,kBAAA,CAAA,UAAA,CAAA,MAAA,CAAA,gBAAA,CAAA,KAAA,CAAA,WAEA,WAAA,OACA,YAAA,IACA,YAAA,IACA,WAAA,KACA,WAAA,MACA,gBAAA,KACA,YAAA,KACA,eAAA,KACA,eAAA,OACA,WAAA,OACA,aAAA,OACA,YAAA,OACA,WAAA,KCLA,UAAA,QAEA,UAAA,WACA,iBAAA,KACA,gBAAA,YACA,OAAA,IAAA,MAAA,ezCZE,cAAA,MyCJJ,gBAyBI,SAAA,SACA,QAAA,MACA,MAAA,KACA,OAAA,IjD0vJJ,uBiDtxJA,wBAiCI,SAAA,SACA,QAAA,MACA,aAAA,YACA,aAAA,MApCJ,wBAwCI,QAAA,GACA,aAAA,KAzCJ,uBA4CI,QAAA,GACA,aAAA,KA7CJ,2CAAA,wBAmDI,cAAA,KAnDJ,kDAAA,+BAsDM,OAAA,EjD0vJiC,yDiDhzJvC,0DjDgzJA,sCiDhzJA,uCA2DM,oBAAA,EA3DN,0DAAA,uCA+DM,OAAA,MACA,YAAA,KACA,iBAAA,gBAjEN,yDAAA,sCAqEM,OAAA,MACA,YAAA,KACA,iBAAA,KAvEN,6CAAA,0BA4EI,YAAA,KA5EJ,oDAAA,iCA+EM,KAAA,EjD0vJmC,2DiDz0JzC,4DjDy0JA,wCiDz0JA,yCAoFM,WAAA,KACA,kBAAA,EArFN,4DAAA,yCAyFM,KAAA,MACA,mBAAA,gBA1FN,2DAAA,wCA8FM,KAAA,MACA,mBAAA,KA/FN,8CAAA,2BAoGI,WAAA,KApGJ,qDAAA,kCAuGM,IAAA,EjD0vJoC,4DiDj2J1C,6DjDi2JA,yCiDj2JA,0CA4GM,YAAA,KACA,iBAAA,EA7GN,6DAAA,0CAiHM,IAAA,MACA,oBAAA,gBAlHN,4DAAA,yCAsHM,IAAA,MACA,oBAAA,KAvHN,sEAAA,mDA4HM,SAAA,SACA,IAAA,EACA,KAAA,IACA,QAAA,MACA,MAAA,KACA,YAAA,MACA,QAAA,GACA,cAAA,IAAA,MAAA,QAnIN,4CAAA,yBAwII,aAAA,KAxIJ,mDAAA,gCA2IM,MAAA,EjDyvJkC,0DiDp4JxC,2DjDo4JA,uCiDp4JA,wCAgJM,WAAA,KACA,mBAAA,EAjJN,2DAAA,wCAqJM,MAAA,MACA,kBAAA,gBAtJN,0DAAA,uCA0JM,MAAA,MACA,kBAAA,KAqBN,gBACE,QAAA,IAAA,KACA,cAAA,EACA,UAAA,KACA,MAAA,QACA,iBAAA,QACA,cAAA,IAAA,MAAA,QzC5KE,uBAAA,kBACA,wBAAA,kByCqKJ,sBAWI,QAAA,KAIJ,cACE,QAAA,IAAA,KACA,MAAA,QChMF,UACE,SAAA,SAGF,gBACE,SAAA,SACA,MAAA,KACA,SAAA,OAGF,eACE,SAAA,SACA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,MAAA,KzCVI,WAAA,kBAAA,IAAA,KAAA,WAAA,UAAA,IAAA,KAAA,WAAA,UAAA,IAAA,IAAA,CAAA,kBAAA,IAAA,KyCYJ,4BAAA,OAAA,oBAAA,OACA,oBAAA,OAAA,YAAA,OlD+6JF,oBACA,oBkD76JA,sBAGE,QAAA,MAGF,oBlD46JA,oBkD16JE,SAAA,SACA,IAAA,EAIF,uClD26JA,wCkDz6JE,kBAAA,cAAA,UAAA,cAEwC,mFAJ1C,uClDk7JE,wCkD76JE,kBAAA,mBAAA,UAAA,oBlDo7JJ,4BkDh7JA,oBAEE,kBAAA,iBAAA,UAAA,iBAEwC,mFlDm7JxC,4BkDv7JF,oBAKI,kBAAA,sBAAA,UAAA,uBlDy7JJ,2BkDr7JA,oBAEE,kBAAA,kBAAA,UAAA,kBAEwC,mFlDw7JxC,2BkD57JF,oBAKI,kBAAA,uBAAA,UAAA,wBlD87JJ,uBkDr7JA,uBAEE,SAAA,SACA,IAAA,EACA,OAAA,EAEA,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,OAAA,gBAAA,OACA,MAAA,IACA,MAAA,KACA,WAAA,OACA,QAAA,GlD07JF,6BACA,6BGn/JI,6BAAA,6B+C8DA,MAAA,KACA,gBAAA,KACA,QAAA,EACA,QAAA,GAGJ,uBACE,KAAA,EAEF,uBACE,MAAA,ElD27JF,4BkDv7JA,4BAEE,QAAA,aACA,MAAA,KACA,OAAA,KACA,WAAA,YAAA,UAAA,OAAA,OACA,gBAAA,KAAA,KAEF,4BACE,iBAAA,4LAEF,4BACE,iBAAA,8LASF,qBACE,SAAA,SACA,MAAA,EACA,OAAA,KACA,KAAA,EACA,QAAA,GACA,QAAA,YAAA,QAAA,KACA,cAAA,OAAA,gBAAA,OACA,aAAA,EAEA,aAAA,IACA,YAAA,IACA,WAAA,KAZF,wBAeI,SAAA,SACA,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,KACA,OAAA,IACA,aAAA,IACA,YAAA,IACA,YAAA,OACA,iBAAA,qBAtBJ,gCA0BM,SAAA,SACA,IAAA,MACA,KAAA,EACA,QAAA,aACA,MAAA,KACA,OAAA,KACA,QAAA,GAhCN,+BAmCM,SAAA,SACA,OAAA,MACA,KAAA,EACA,QAAA,aACA,MAAA,KACA,OAAA,KACA,QAAA,GAzCN,6BA8CI,iBAAA,KASJ,kBACE,SAAA,SACA,MAAA,IACA,OAAA,KACA,KAAA,IACA,QAAA,GACA,YAAA,KACA,eAAA,KACA,MAAA,KACA,WAAA,OCvLF,gBAAqB,eAAA,mBACrB,WAAqB,eAAA,cACrB,cAAqB,eAAA,iBACrB,cAAqB,eAAA,iBACrB,mBAAqB,eAAA,sBACrB,gBAAqB,eAAA,mBCFnB,YACE,iBAAA,kBjDkBA,mBAAA,mBiDdE,iBAAA,kBALJ,cACE,iBAAA,kBjDkBA,qBAAA,qBiDdE,iBAAA,kBALJ,YACE,iBAAA,kBjDkBA,mBAAA,mBiDdE,iBAAA,kBALJ,SACE,iBAAA,kBjDkBA,gBAAA,gBiDdE,iBAAA,kBALJ,YACE,iBAAA,kBjDkBA,mBAAA,mBiDdE,iBAAA,kBALJ,WACE,iBAAA,kBjDkBA,kBAAA,kBiDdE,iBAAA,kBALJ,UACE,iBAAA,kBjDkBA,iBAAA,iBiDdE,iBAAA,kBALJ,SACE,iBAAA,kBjDkBA,gBAAA,gBiDdE,iBAAA,kBCJN,gBAAkB,iBAAA,sBCAlB,QAAmB,OAAA,IAAA,MAAA,kBACnB,UAAmB,OAAA,YACnB,cAAmB,WAAA,YACnB,gBAAmB,aAAA,YACnB,iBAAmB,cAAA,YACnB,eAAmB,YAAA,YAGjB,gBACE,aAAA,kBADF,kBACE,aAAA,kBADF,gBACE,aAAA,kBADF,aACE,aAAA,kBADF,gBACE,aAAA,kBADF,eACE,aAAA,kBADF,cACE,aAAA,kBADF,aACE,aAAA,kBAQJ,SACE,cAAA,iBAEF,aACE,uBAAA,iBACA,wBAAA,iBAEF,eACE,wBAAA,iBACA,2BAAA,iBAEF,gBACE,2BAAA,iBACA,0BAAA,iBAEF,cACE,uBAAA,iBACA,0BAAA,iBAGF,gBACE,cAAA,IAGF,WACE,cAAA,EtB7CA,iBACE,QAAA,MACA,MAAA,KACA,QAAA,GuBIA,QAA2B,QAAA,eAC3B,UAA2B,QAAA,iBAC3B,gBAA2B,QAAA,uBAC3B,SAA2B,QAAA,gBAC3B,SAA2B,QAAA,gBAC3B,cAA2B,QAAA,qBAC3B,QAA2B,QAAA,sBAAA,QAAA,eAC3B,eAA2B,QAAA,6BAAA,QAAA,sB1CyC3B,yB0ChDA,WAA2B,QAAA,eAC3B,aAA2B,QAAA,iBAC3B,mBAA2B,QAAA,uBAC3B,YAA2B,QAAA,gBAC3B,YAA2B,QAAA,gBAC3B,iBAA2B,QAAA,qBAC3B,WAA2B,QAAA,sBAAA,QAAA,eAC3B,kBAA2B,QAAA,6BAAA,QAAA,uB1CyC3B,yB0ChDA,WAA2B,QAAA,eAC3B,aAA2B,QAAA,iBAC3B,mBAA2B,QAAA,uBAC3B,YAA2B,QAAA,gBAC3B,YAA2B,QAAA,gBAC3B,iBAA2B,QAAA,qBAC3B,WAA2B,QAAA,sBAAA,QAAA,eAC3B,kBAA2B,QAAA,6BAAA,QAAA,uB1CyC3B,yB0ChDA,WAA2B,QAAA,eAC3B,aAA2B,QAAA,iBAC3B,mBAA2B,QAAA,uBAC3B,YAA2B,QAAA,gBAC3B,YAA2B,QAAA,gBAC3B,iBAA2B,QAAA,qBAC3B,WAA2B,QAAA,sBAAA,QAAA,eAC3B,kBAA2B,QAAA,6BAAA,QAAA,uB1CyC3B,0B0ChDA,WAA2B,QAAA,eAC3B,aAA2B,QAAA,iBAC3B,mBAA2B,QAAA,uBAC3B,YAA2B,QAAA,gBAC3B,YAA2B,QAAA,gBAC3B,iBAA2B,QAAA,qBAC3B,WAA2B,QAAA,sBAAA,QAAA,eAC3B,kBAA2B,QAAA,6BAAA,QAAA,uBAS/B,eACE,QAAA,eAEA,aAHF,eAII,QAAA,iBAIJ,gBACE,QAAA,eAEA,aAHF,gBAII,QAAA,kBAIJ,sBACE,QAAA,eAEA,aAHF,sBAII,QAAA,wBAKF,aADF,cAEI,QAAA,gBChDJ,kBACE,SAAA,SACA,QAAA,MACA,MAAA,KACA,QAAA,EACA,SAAA,OALF,0BAQI,QAAA,MACA,QAAA,GATJ,yCxD0+KA,wBADA,yBAEA,yBACA,wBwD39KI,SAAA,SACA,IAAA,EACA,OAAA,EACA,KAAA,EACA,MAAA,KACA,OAAA,KACA,OAAA,EAIJ,gCAEI,YAAA,WAIJ,gCAEI,YAAA,OAIJ,+BAEI,YAAA,IAIJ,+BAEI,YAAA,KCzCA,UAAgC,mBAAA,cAAA,eAAA,cAChC,aAAgC,mBAAA,iBAAA,eAAA,iBAChC,kBAAgC,mBAAA,sBAAA,eAAA,sBAChC,qBAAgC,mBAAA,yBAAA,eAAA,yBAEhC,WAA8B,cAAA,eAAA,UAAA,eAC9B,aAA8B,cAAA,iBAAA,UAAA,iBAC9B,mBAA8B,cAAA,uBAAA,UAAA,uBAE9B,uBAAoC,cAAA,gBAAA,gBAAA,qBACpC,qBAAoC,cAAA,cAAA,gBAAA,mBACpC,wBAAoC,cAAA,iBAAA,gBAAA,iBACpC,yBAAoC,cAAA,kBAAA,gBAAA,wBACpC,wBAAoC,cAAA,qBAAA,gBAAA,uBAEpC,mBAAiC,eAAA,gBAAA,YAAA,qBACjC,iBAAiC,eAAA,cAAA,YAAA,mBACjC,oBAAiC,eAAA,iBAAA,YAAA,iBACjC,sBAAiC,eAAA,mBAAA,YAAA,mBACjC,qBAAiC,eAAA,kBAAA,YAAA,kBAEjC,qBAAkC,mBAAA,gBAAA,cAAA,qBAClC,mBAAkC,mBAAA,cAAA,cAAA,mBAClC,sBAAkC,mBAAA,iBAAA,cAAA,iBAClC,uBAAkC,mBAAA,kBAAA,cAAA,wBAClC,sBAAkC,mBAAA,qBAAA,cAAA,uBAClC,uBAAkC,mBAAA,kBAAA,cAAA,kBAElC,iBAAgC,oBAAA,eAAA,WAAA,eAChC,kBAAgC,oBAAA,gBAAA,WAAA,qBAChC,gBAAgC,oBAAA,cAAA,WAAA,mBAChC,mBAAgC,oBAAA,iBAAA,WAAA,iBAChC,qBAAgC,oBAAA,mBAAA,WAAA,mBAChC,oBAAgC,oBAAA,kBAAA,WAAA,kB5CehC,yB4ChDA,aAAgC,mBAAA,cAAA,eAAA,cAChC,gBAAgC,mBAAA,iBAAA,eAAA,iBAChC,qBAAgC,mBAAA,sBAAA,eAAA,sBAChC,wBAAgC,mBAAA,yBAAA,eAAA,yBAEhC,cAA8B,cAAA,eAAA,UAAA,eAC9B,gBAA8B,cAAA,iBAAA,UAAA,iBAC9B,sBAA8B,cAAA,uBAAA,UAAA,uBAE9B,0BAAoC,cAAA,gBAAA,gBAAA,qBACpC,wBAAoC,cAAA,cAAA,gBAAA,mBACpC,2BAAoC,cAAA,iBAAA,gBAAA,iBACpC,4BAAoC,cAAA,kBAAA,gBAAA,wBACpC,2BAAoC,cAAA,qBAAA,gBAAA,uBAEpC,sBAAiC,eAAA,gBAAA,YAAA,qBACjC,oBAAiC,eAAA,cAAA,YAAA,mBACjC,uBAAiC,eAAA,iBAAA,YAAA,iBACjC,yBAAiC,eAAA,mBAAA,YAAA,mBACjC,wBAAiC,eAAA,kBAAA,YAAA,kBAEjC,wBAAkC,mBAAA,gBAAA,cAAA,qBAClC,sBAAkC,mBAAA,cAAA,cAAA,mBAClC,yBAAkC,mBAAA,iBAAA,cAAA,iBAClC,0BAAkC,mBAAA,kBAAA,cAAA,wBAClC,yBAAkC,mBAAA,qBAAA,cAAA,uBAClC,0BAAkC,mBAAA,kBAAA,cAAA,kBAElC,oBAAgC,oBAAA,eAAA,WAAA,eAChC,qBAAgC,oBAAA,gBAAA,WAAA,qBAChC,mBAAgC,oBAAA,cAAA,WAAA,mBAChC,sBAAgC,oBAAA,iBAAA,WAAA,iBAChC,wBAAgC,oBAAA,mBAAA,WAAA,mBAChC,uBAAgC,oBAAA,kBAAA,WAAA,mB5CehC,yB4ChDA,aAAgC,mBAAA,cAAA,eAAA,cAChC,gBAAgC,mBAAA,iBAAA,eAAA,iBAChC,qBAAgC,mBAAA,sBAAA,eAAA,sBAChC,wBAAgC,mBAAA,yBAAA,eAAA,yBAEhC,cAA8B,cAAA,eAAA,UAAA,eAC9B,gBAA8B,cAAA,iBAAA,UAAA,iBAC9B,sBAA8B,cAAA,uBAAA,UAAA,uBAE9B,0BAAoC,cAAA,gBAAA,gBAAA,qBACpC,wBAAoC,cAAA,cAAA,gBAAA,mBACpC,2BAAoC,cAAA,iBAAA,gBAAA,iBACpC,4BAAoC,cAAA,kBAAA,gBAAA,wBACpC,2BAAoC,cAAA,qBAAA,gBAAA,uBAEpC,sBAAiC,eAAA,gBAAA,YAAA,qBACjC,oBAAiC,eAAA,cAAA,YAAA,mBACjC,uBAAiC,eAAA,iBAAA,YAAA,iBACjC,yBAAiC,eAAA,mBAAA,YAAA,mBACjC,wBAAiC,eAAA,kBAAA,YAAA,kBAEjC,wBAAkC,mBAAA,gBAAA,cAAA,qBAClC,sBAAkC,mBAAA,cAAA,cAAA,mBAClC,yBAAkC,mBAAA,iBAAA,cAAA,iBAClC,0BAAkC,mBAAA,kBAAA,cAAA,wBAClC,yBAAkC,mBAAA,qBAAA,cAAA,uBAClC,0BAAkC,mBAAA,kBAAA,cAAA,kBAElC,oBAAgC,oBAAA,eAAA,WAAA,eAChC,qBAAgC,oBAAA,gBAAA,WAAA,qBAChC,mBAAgC,oBAAA,cAAA,WAAA,mBAChC,sBAAgC,oBAAA,iBAAA,WAAA,iBAChC,wBAAgC,oBAAA,mBAAA,WAAA,mBAChC,uBAAgC,oBAAA,kBAAA,WAAA,mB5CehC,yB4ChDA,aAAgC,mBAAA,cAAA,eAAA,cAChC,gBAAgC,mBAAA,iBAAA,eAAA,iBAChC,qBAAgC,mBAAA,sBAAA,eAAA,sBAChC,wBAAgC,mBAAA,yBAAA,eAAA,yBAEhC,cAA8B,cAAA,eAAA,UAAA,eAC9B,gBAA8B,cAAA,iBAAA,UAAA,iBAC9B,sBAA8B,cAAA,uBAAA,UAAA,uBAE9B,0BAAoC,cAAA,gBAAA,gBAAA,qBACpC,wBAAoC,cAAA,cAAA,gBAAA,mBACpC,2BAAoC,cAAA,iBAAA,gBAAA,iBACpC,4BAAoC,cAAA,kBAAA,gBAAA,wBACpC,2BAAoC,cAAA,qBAAA,gBAAA,uBAEpC,sBAAiC,eAAA,gBAAA,YAAA,qBACjC,oBAAiC,eAAA,cAAA,YAAA,mBACjC,uBAAiC,eAAA,iBAAA,YAAA,iBACjC,yBAAiC,eAAA,mBAAA,YAAA,mBACjC,wBAAiC,eAAA,kBAAA,YAAA,kBAEjC,wBAAkC,mBAAA,gBAAA,cAAA,qBAClC,sBAAkC,mBAAA,cAAA,cAAA,mBAClC,yBAAkC,mBAAA,iBAAA,cAAA,iBAClC,0BAAkC,mBAAA,kBAAA,cAAA,wBAClC,yBAAkC,mBAAA,qBAAA,cAAA,uBAClC,0BAAkC,mBAAA,kBAAA,cAAA,kBAElC,oBAAgC,oBAAA,eAAA,WAAA,eAChC,qBAAgC,oBAAA,gBAAA,WAAA,qBAChC,mBAAgC,oBAAA,cAAA,WAAA,mBAChC,sBAAgC,oBAAA,iBAAA,WAAA,iBAChC,wBAAgC,oBAAA,mBAAA,WAAA,mBAChC,uBAAgC,oBAAA,kBAAA,WAAA,mB5CehC,0B4ChDA,aAAgC,mBAAA,cAAA,eAAA,cAChC,gBAAgC,mBAAA,iBAAA,eAAA,iBAChC,qBAAgC,mBAAA,sBAAA,eAAA,sBAChC,wBAAgC,mBAAA,yBAAA,eAAA,yBAEhC,cAA8B,cAAA,eAAA,UAAA,eAC9B,gBAA8B,cAAA,iBAAA,UAAA,iBAC9B,sBAA8B,cAAA,uBAAA,UAAA,uBAE9B,0BAAoC,cAAA,gBAAA,gBAAA,qBACpC,wBAAoC,cAAA,cAAA,gBAAA,mBACpC,2BAAoC,cAAA,iBAAA,gBAAA,iBACpC,4BAAoC,cAAA,kBAAA,gBAAA,wBACpC,2BAAoC,cAAA,qBAAA,gBAAA,uBAEpC,sBAAiC,eAAA,gBAAA,YAAA,qBACjC,oBAAiC,eAAA,cAAA,YAAA,mBACjC,uBAAiC,eAAA,iBAAA,YAAA,iBACjC,yBAAiC,eAAA,mBAAA,YAAA,mBACjC,wBAAiC,eAAA,kBAAA,YAAA,kBAEjC,wBAAkC,mBAAA,gBAAA,cAAA,qBAClC,sBAAkC,mBAAA,cAAA,cAAA,mBAClC,yBAAkC,mBAAA,iBAAA,cAAA,iBAClC,0BAAkC,mBAAA,kBAAA,cAAA,wBAClC,yBAAkC,mBAAA,qBAAA,cAAA,uBAClC,0BAAkC,mBAAA,kBAAA,cAAA,kBAElC,oBAAgC,oBAAA,eAAA,WAAA,eAChC,qBAAgC,oBAAA,gBAAA,WAAA,qBAChC,mBAAgC,oBAAA,cAAA,WAAA,mBAChC,sBAAgC,oBAAA,iBAAA,WAAA,iBAChC,wBAAgC,oBAAA,mBAAA,WAAA,mBAChC,uBAAgC,oBAAA,kBAAA,WAAA,mBCrChC,YCHF,MAAA,eDIE,aCDF,MAAA,gBDEE,YCCF,MAAA,e9CiDE,yB6CpDA,eCHF,MAAA,eDIE,gBCDF,MAAA,gBDEE,eCCF,MAAA,gB9CiDE,yB6CpDA,eCHF,MAAA,eDIE,gBCDF,MAAA,gBDEE,eCCF,MAAA,gB9CiDE,yB6CpDA,eCHF,MAAA,eDIE,gBCDF,MAAA,gBDEE,eCCF,MAAA,gB9CiDE,0B6CpDA,eCHF,MAAA,eDIE,gBCDF,MAAA,gBDEE,eCCF,MAAA,gBCLF,WACE,SAAA,MACA,IAAA,EACA,MAAA,EACA,KAAA,EACA,QAAA,KAGF,cACE,SAAA,MACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,KAI4B,2DAD9B,YAEI,SAAA,eAAA,SAAA,OACA,IAAA,EACA,QAAA,MClBJ,SCEE,SAAA,SACA,MAAA,IACA,OAAA,IACA,QAAA,EACA,SAAA,OACA,KAAA,cACA,YAAA,OACA,kBAAA,WAAA,UAAA,WACA,OAAA,EAUA,0BAAA,yBAEE,SAAA,OACA,MAAA,KACA,OAAA,KACA,SAAA,QACA,KAAA,KACA,YAAA,OACA,kBAAA,KAAA,UAAA,KC5BA,MAAuB,MAAA,cAAvB,MAAuB,MAAA,cAAvB,MAAuB,MAAA,cAAvB,OAAuB,MAAA,eAAvB,MAAuB,OAAA,cAAvB,MAAuB,OAAA,cAAvB,MAAuB,OAAA,cAAvB,OAAuB,OAAA,eAI3B,QAAU,UAAA,eACV,QAAU,WAAA,eCAF,KAAiC,OAAA,YACjC,MAAiC,WAAA,YACjC,MAAiC,aAAA,YACjC,MAAiC,cAAA,YACjC,MAAiC,YAAA,YACjC,MACE,aAAA,YACA,YAAA,YAEF,MACE,WAAA,YACA,cAAA,YAXF,KAAiC,OAAA,iBACjC,MAAiC,WAAA,iBACjC,MAAiC,aAAA,iBACjC,MAAiC,cAAA,iBACjC,MAAiC,YAAA,iBACjC,MACE,aAAA,iBACA,YAAA,iBAEF,MACE,WAAA,iBACA,cAAA,iBAXF,KAAiC,OAAA,gBACjC,MAAiC,WAAA,gBACjC,MAAiC,aAAA,gBACjC,MAAiC,cAAA,gBACjC,MAAiC,YAAA,gBACjC,MACE,aAAA,gBACA,YAAA,gBAEF,MACE,WAAA,gBACA,cAAA,gBAXF,KAAiC,OAAA,eACjC,MAAiC,WAAA,eACjC,MAAiC,aAAA,eACjC,MAAiC,cAAA,eACjC,MAAiC,YAAA,eACjC,MACE,aAAA,eACA,YAAA,eAEF,MACE,WAAA,eACA,cAAA,eAXF,KAAiC,OAAA,iBACjC,MAAiC,WAAA,iBACjC,MAAiC,aAAA,iBACjC,MAAiC,cAAA,iBACjC,MAAiC,YAAA,iBACjC,MACE,aAAA,iBACA,YAAA,iBAEF,MACE,WAAA,iBACA,cAAA,iBAXF,KAAiC,OAAA,eACjC,MAAiC,WAAA,eACjC,MAAiC,aAAA,eACjC,MAAiC,cAAA,eACjC,MAAiC,YAAA,eACjC,MACE,aAAA,eACA,YAAA,eAEF,MACE,WAAA,eACA,cAAA,eAXF,KAAiC,QAAA,YACjC,MAAiC,YAAA,YACjC,MAAiC,cAAA,YACjC,MAAiC,eAAA,YACjC,MAAiC,aAAA,YACjC,MACE,cAAA,YACA,aAAA,YAEF,MACE,YAAA,YACA,eAAA,YAXF,KAAiC,QAAA,iBACjC,MAAiC,YAAA,iBACjC,MAAiC,cAAA,iBACjC,MAAiC,eAAA,iBACjC,MAAiC,aAAA,iBACjC,MACE,cAAA,iBACA,aAAA,iBAEF,MACE,YAAA,iBACA,eAAA,iBAXF,KAAiC,QAAA,gBACjC,MAAiC,YAAA,gBACjC,MAAiC,cAAA,gBACjC,MAAiC,eAAA,gBACjC,MAAiC,aAAA,gBACjC,MACE,cAAA,gBACA,aAAA,gBAEF,MACE,YAAA,gBACA,eAAA,gBAXF,KAAiC,QAAA,eACjC,MAAiC,YAAA,eACjC,MAAiC,cAAA,eACjC,MAAiC,eAAA,eACjC,MAAiC,aAAA,eACjC,MACE,cAAA,eACA,aAAA,eAEF,MACE,YAAA,eACA,eAAA,eAXF,KAAiC,QAAA,iBACjC,MAAiC,YAAA,iBACjC,MAAiC,cAAA,iBACjC,MAAiC,eAAA,iBACjC,MAAiC,aAAA,iBACjC,MACE,cAAA,iBACA,aAAA,iBAEF,MACE,YAAA,iBACA,eAAA,iBAXF,KAAiC,QAAA,eACjC,MAAiC,YAAA,eACjC,MAAiC,cAAA,eACjC,MAAiC,eAAA,eACjC,MAAiC,aAAA,eACjC,MACE,cAAA,eACA,aAAA,eAEF,MACE,YAAA,eACA,eAAA,eAMN,QAAoB,OAAA,eACpB,SAAoB,WAAA,eACpB,SAAoB,aAAA,eACpB,SAAoB,cAAA,eACpB,SAAoB,YAAA,eACpB,SACE,aAAA,eACA,YAAA,eAEF,SACE,WAAA,eACA,cAAA,enDmBF,yBmD/CI,QAAiC,OAAA,YACjC,SAAiC,WAAA,YACjC,SAAiC,aAAA,YACjC,SAAiC,cAAA,YACjC,SAAiC,YAAA,YACjC,SACE,aAAA,YACA,YAAA,YAEF,SACE,WAAA,YACA,cAAA,YAXF,QAAiC,OAAA,iBACjC,SAAiC,WAAA,iBACjC,SAAiC,aAAA,iBACjC,SAAiC,cAAA,iBACjC,SAAiC,YAAA,iBACjC,SACE,aAAA,iBACA,YAAA,iBAEF,SACE,WAAA,iBACA,cAAA,iBAXF,QAAiC,OAAA,gBACjC,SAAiC,WAAA,gBACjC,SAAiC,aAAA,gBACjC,SAAiC,cAAA,gBACjC,SAAiC,YAAA,gBACjC,SACE,aAAA,gBACA,YAAA,gBAEF,SACE,WAAA,gBACA,cAAA,gBAXF,QAAiC,OAAA,eACjC,SAAiC,WAAA,eACjC,SAAiC,aAAA,eACjC,SAAiC,cAAA,eACjC,SAAiC,YAAA,eACjC,SACE,aAAA,eACA,YAAA,eAEF,SACE,WAAA,eACA,cAAA,eAXF,QAAiC,OAAA,iBACjC,SAAiC,WAAA,iBACjC,SAAiC,aAAA,iBACjC,SAAiC,cAAA,iBACjC,SAAiC,YAAA,iBACjC,SACE,aAAA,iBACA,YAAA,iBAEF,SACE,WAAA,iBACA,cAAA,iBAXF,QAAiC,OAAA,eACjC,SAAiC,WAAA,eACjC,SAAiC,aAAA,eACjC,SAAiC,cAAA,eACjC,SAAiC,YAAA,eACjC,SACE,aAAA,eACA,YAAA,eAEF,SACE,WAAA,eACA,cAAA,eAXF,QAAiC,QAAA,YACjC,SAAiC,YAAA,YACjC,SAAiC,cAAA,YACjC,SAAiC,eAAA,YACjC,SAAiC,aAAA,YACjC,SACE,cAAA,YACA,aAAA,YAEF,SACE,YAAA,YACA,eAAA,YAXF,QAAiC,QAAA,iBACjC,SAAiC,YAAA,iBACjC,SAAiC,cAAA,iBACjC,SAAiC,eAAA,iBACjC,SAAiC,aAAA,iBACjC,SACE,cAAA,iBACA,aAAA,iBAEF,SACE,YAAA,iBACA,eAAA,iBAXF,QAAiC,QAAA,gBACjC,SAAiC,YAAA,gBACjC,SAAiC,cAAA,gBACjC,SAAiC,eAAA,gBACjC,SAAiC,aAAA,gBACjC,SACE,cAAA,gBACA,aAAA,gBAEF,SACE,YAAA,gBACA,eAAA,gBAXF,QAAiC,QAAA,eACjC,SAAiC,YAAA,eACjC,SAAiC,cAAA,eACjC,SAAiC,eAAA,eACjC,SAAiC,aAAA,eACjC,SACE,cAAA,eACA,aAAA,eAEF,SACE,YAAA,eACA,eAAA,eAXF,QAAiC,QAAA,iBACjC,SAAiC,YAAA,iBACjC,SAAiC,cAAA,iBACjC,SAAiC,eAAA,iBACjC,SAAiC,aAAA,iBACjC,SACE,cAAA,iBACA,aAAA,iBAEF,SACE,YAAA,iBACA,eAAA,iBAXF,QAAiC,QAAA,eACjC,SAAiC,YAAA,eACjC,SAAiC,cAAA,eACjC,SAAiC,eAAA,eACjC,SAAiC,aAAA,eACjC,SACE,cAAA,eACA,aAAA,eAEF,SACE,YAAA,eACA,eAAA,eAMN,WAAoB,OAAA,eACpB,YAAoB,WAAA,eACpB,YAAoB,aAAA,eACpB,YAAoB,cAAA,eACpB,YAAoB,YAAA,eACpB,YACE,aAAA,eACA,YAAA,eAEF,YACE,WAAA,eACA,cAAA,gBnDmBF,yBmD/CI,QAAiC,OAAA,YACjC,SAAiC,WAAA,YACjC,SAAiC,aAAA,YACjC,SAAiC,cAAA,YACjC,SAAiC,YAAA,YACjC,SACE,aAAA,YACA,YAAA,YAEF,SACE,WAAA,YACA,cAAA,YAXF,QAAiC,OAAA,iBACjC,SAAiC,WAAA,iBACjC,SAAiC,aAAA,iBACjC,SAAiC,cAAA,iBACjC,SAAiC,YAAA,iBACjC,SACE,aAAA,iBACA,YAAA,iBAEF,SACE,WAAA,iBACA,cAAA,iBAXF,QAAiC,OAAA,gBACjC,SAAiC,WAAA,gBACjC,SAAiC,aAAA,gBACjC,SAAiC,cAAA,gBACjC,SAAiC,YAAA,gBACjC,SACE,aAAA,gBACA,YAAA,gBAEF,SACE,WAAA,gBACA,cAAA,gBAXF,QAAiC,OAAA,eACjC,SAAiC,WAAA,eACjC,SAAiC,aAAA,eACjC,SAAiC,cAAA,eACjC,SAAiC,YAAA,eACjC,SACE,aAAA,eACA,YAAA,eAEF,SACE,WAAA,eACA,cAAA,eAXF,QAAiC,OAAA,iBACjC,SAAiC,WAAA,iBACjC,SAAiC,aAAA,iBACjC,SAAiC,cAAA,iBACjC,SAAiC,YAAA,iBACjC,SACE,aAAA,iBACA,YAAA,iBAEF,SACE,WAAA,iBACA,cAAA,iBAXF,QAAiC,OAAA,eACjC,SAAiC,WAAA,eACjC,SAAiC,aAAA,eACjC,SAAiC,cAAA,eACjC,SAAiC,YAAA,eACjC,SACE,aAAA,eACA,YAAA,eAEF,SACE,WAAA,eACA,cAAA,eAXF,QAAiC,QAAA,YACjC,SAAiC,YAAA,YACjC,SAAiC,cAAA,YACjC,SAAiC,eAAA,YACjC,SAAiC,aAAA,YACjC,SACE,cAAA,YACA,aAAA,YAEF,SACE,YAAA,YACA,eAAA,YAXF,QAAiC,QAAA,iBACjC,SAAiC,YAAA,iBACjC,SAAiC,cAAA,iBACjC,SAAiC,eAAA,iBACjC,SAAiC,aAAA,iBACjC,SACE,cAAA,iBACA,aAAA,iBAEF,SACE,YAAA,iBACA,eAAA,iBAXF,QAAiC,QAAA,gBACjC,SAAiC,YAAA,gBACjC,SAAiC,cAAA,gBACjC,SAAiC,eAAA,gBACjC,SAAiC,aAAA,gBACjC,SACE,cAAA,gBACA,aAAA,gBAEF,SACE,YAAA,gBACA,eAAA,gBAXF,QAAiC,QAAA,eACjC,SAAiC,YAAA,eACjC,SAAiC,cAAA,eACjC,SAAiC,eAAA,eACjC,SAAiC,aAAA,eACjC,SACE,cAAA,eACA,aAAA,eAEF,SACE,YAAA,eACA,eAAA,eAXF,QAAiC,QAAA,iBACjC,SAAiC,YAAA,iBACjC,SAAiC,cAAA,iBACjC,SAAiC,eAAA,iBACjC,SAAiC,aAAA,iBACjC,SACE,cAAA,iBACA,aAAA,iBAEF,SACE,YAAA,iBACA,eAAA,iBAXF,QAAiC,QAAA,eACjC,SAAiC,YAAA,eACjC,SAAiC,cAAA,eACjC,SAAiC,eAAA,eACjC,SAAiC,aAAA,eACjC,SACE,cAAA,eACA,aAAA,eAEF,SACE,YAAA,eACA,eAAA,eAMN,WAAoB,OAAA,eACpB,YAAoB,WAAA,eACpB,YAAoB,aAAA,eACpB,YAAoB,cAAA,eACpB,YAAoB,YAAA,eACpB,YACE,aAAA,eACA,YAAA,eAEF,YACE,WAAA,eACA,cAAA,gBnDmBF,yBmD/CI,QAAiC,OAAA,YACjC,SAAiC,WAAA,YACjC,SAAiC,aAAA,YACjC,SAAiC,cAAA,YACjC,SAAiC,YAAA,YACjC,SACE,aAAA,YACA,YAAA,YAEF,SACE,WAAA,YACA,cAAA,YAXF,QAAiC,OAAA,iBACjC,SAAiC,WAAA,iBACjC,SAAiC,aAAA,iBACjC,SAAiC,cAAA,iBACjC,SAAiC,YAAA,iBACjC,SACE,aAAA,iBACA,YAAA,iBAEF,SACE,WAAA,iBACA,cAAA,iBAXF,QAAiC,OAAA,gBACjC,SAAiC,WAAA,gBACjC,SAAiC,aAAA,gBACjC,SAAiC,cAAA,gBACjC,SAAiC,YAAA,gBACjC,SACE,aAAA,gBACA,YAAA,gBAEF,SACE,WAAA,gBACA,cAAA,gBAXF,QAAiC,OAAA,eACjC,SAAiC,WAAA,eACjC,SAAiC,aAAA,eACjC,SAAiC,cAAA,eACjC,SAAiC,YAAA,eACjC,SACE,aAAA,eACA,YAAA,eAEF,SACE,WAAA,eACA,cAAA,eAXF,QAAiC,OAAA,iBACjC,SAAiC,WAAA,iBACjC,SAAiC,aAAA,iBACjC,SAAiC,cAAA,iBACjC,SAAiC,YAAA,iBACjC,SACE,aAAA,iBACA,YAAA,iBAEF,SACE,WAAA,iBACA,cAAA,iBAXF,QAAiC,OAAA,eACjC,SAAiC,WAAA,eACjC,SAAiC,aAAA,eACjC,SAAiC,cAAA,eACjC,SAAiC,YAAA,eACjC,SACE,aAAA,eACA,YAAA,eAEF,SACE,WAAA,eACA,cAAA,eAXF,QAAiC,QAAA,YACjC,SAAiC,YAAA,YACjC,SAAiC,cAAA,YACjC,SAAiC,eAAA,YACjC,SAAiC,aAAA,YACjC,SACE,cAAA,YACA,aAAA,YAEF,SACE,YAAA,YACA,eAAA,YAXF,QAAiC,QAAA,iBACjC,SAAiC,YAAA,iBACjC,SAAiC,cAAA,iBACjC,SAAiC,eAAA,iBACjC,SAAiC,aAAA,iBACjC,SACE,cAAA,iBACA,aAAA,iBAEF,SACE,YAAA,iBACA,eAAA,iBAXF,QAAiC,QAAA,gBACjC,SAAiC,YAAA,gBACjC,SAAiC,cAAA,gBACjC,SAAiC,eAAA,gBACjC,SAAiC,aAAA,gBACjC,SACE,cAAA,gBACA,aAAA,gBAEF,SACE,YAAA,gBACA,eAAA,gBAXF,QAAiC,QAAA,eACjC,SAAiC,YAAA,eACjC,SAAiC,cAAA,eACjC,SAAiC,eAAA,eACjC,SAAiC,aAAA,eACjC,SACE,cAAA,eACA,aAAA,eAEF,SACE,YAAA,eACA,eAAA,eAXF,QAAiC,QAAA,iBACjC,SAAiC,YAAA,iBACjC,SAAiC,cAAA,iBACjC,SAAiC,eAAA,iBACjC,SAAiC,aAAA,iBACjC,SACE,cAAA,iBACA,aAAA,iBAEF,SACE,YAAA,iBACA,eAAA,iBAXF,QAAiC,QAAA,eACjC,SAAiC,YAAA,eACjC,SAAiC,cAAA,eACjC,SAAiC,eAAA,eACjC,SAAiC,aAAA,eACjC,SACE,cAAA,eACA,aAAA,eAEF,SACE,YAAA,eACA,eAAA,eAMN,WAAoB,OAAA,eACpB,YAAoB,WAAA,eACpB,YAAoB,aAAA,eACpB,YAAoB,cAAA,eACpB,YAAoB,YAAA,eACpB,YACE,aAAA,eACA,YAAA,eAEF,YACE,WAAA,eACA,cAAA,gBnDmBF,0BmD/CI,QAAiC,OAAA,YACjC,SAAiC,WAAA,YACjC,SAAiC,aAAA,YACjC,SAAiC,cAAA,YACjC,SAAiC,YAAA,YACjC,SACE,aAAA,YACA,YAAA,YAEF,SACE,WAAA,YACA,cAAA,YAXF,QAAiC,OAAA,iBACjC,SAAiC,WAAA,iBACjC,SAAiC,aAAA,iBACjC,SAAiC,cAAA,iBACjC,SAAiC,YAAA,iBACjC,SACE,aAAA,iBACA,YAAA,iBAEF,SACE,WAAA,iBACA,cAAA,iBAXF,QAAiC,OAAA,gBACjC,SAAiC,WAAA,gBACjC,SAAiC,aAAA,gBACjC,SAAiC,cAAA,gBACjC,SAAiC,YAAA,gBACjC,SACE,aAAA,gBACA,YAAA,gBAEF,SACE,WAAA,gBACA,cAAA,gBAXF,QAAiC,OAAA,eACjC,SAAiC,WAAA,eACjC,SAAiC,aAAA,eACjC,SAAiC,cAAA,eACjC,SAAiC,YAAA,eACjC,SACE,aAAA,eACA,YAAA,eAEF,SACE,WAAA,eACA,cAAA,eAXF,QAAiC,OAAA,iBACjC,SAAiC,WAAA,iBACjC,SAAiC,aAAA,iBACjC,SAAiC,cAAA,iBACjC,SAAiC,YAAA,iBACjC,SACE,aAAA,iBACA,YAAA,iBAEF,SACE,WAAA,iBACA,cAAA,iBAXF,QAAiC,OAAA,eACjC,SAAiC,WAAA,eACjC,SAAiC,aAAA,eACjC,SAAiC,cAAA,eACjC,SAAiC,YAAA,eACjC,SACE,aAAA,eACA,YAAA,eAEF,SACE,WAAA,eACA,cAAA,eAXF,QAAiC,QAAA,YACjC,SAAiC,YAAA,YACjC,SAAiC,cAAA,YACjC,SAAiC,eAAA,YACjC,SAAiC,aAAA,YACjC,SACE,cAAA,YACA,aAAA,YAEF,SACE,YAAA,YACA,eAAA,YAXF,QAAiC,QAAA,iBACjC,SAAiC,YAAA,iBACjC,SAAiC,cAAA,iBACjC,SAAiC,eAAA,iBACjC,SAAiC,aAAA,iBACjC,SACE,cAAA,iBACA,aAAA,iBAEF,SACE,YAAA,iBACA,eAAA,iBAXF,QAAiC,QAAA,gBACjC,SAAiC,YAAA,gBACjC,SAAiC,cAAA,gBACjC,SAAiC,eAAA,gBACjC,SAAiC,aAAA,gBACjC,SACE,cAAA,gBACA,aAAA,gBAEF,SACE,YAAA,gBACA,eAAA,gBAXF,QAAiC,QAAA,eACjC,SAAiC,YAAA,eACjC,SAAiC,cAAA,eACjC,SAAiC,eAAA,eACjC,SAAiC,aAAA,eACjC,SACE,cAAA,eACA,aAAA,eAEF,SACE,YAAA,eACA,eAAA,eAXF,QAAiC,QAAA,iBACjC,SAAiC,YAAA,iBACjC,SAAiC,cAAA,iBACjC,SAAiC,eAAA,iBACjC,SAAiC,aAAA,iBACjC,SACE,cAAA,iBACA,aAAA,iBAEF,SACE,YAAA,iBACA,eAAA,iBAXF,QAAiC,QAAA,eACjC,SAAiC,YAAA,eACjC,SAAiC,cAAA,eACjC,SAAiC,eAAA,eACjC,SAAiC,aAAA,eACjC,SACE,cAAA,eACA,aAAA,eAEF,SACE,YAAA,eACA,eAAA,eAMN,WAAoB,OAAA,eACpB,YAAoB,WAAA,eACpB,YAAoB,aAAA,eACpB,YAAoB,cAAA,eACpB,YAAoB,YAAA,eACpB,YACE,aAAA,eACA,YAAA,eAEF,YACE,WAAA,eACA,cAAA,gBC/BN,cAAiB,WAAA,kBACjB,aAAiB,YAAA,iBACjB,eCJE,SAAA,OACA,cAAA,SACA,YAAA,ODUE,WAAwB,WAAA,eACxB,YAAwB,WAAA,gBACxB,aAAwB,WAAA,iBpDsCxB,yBoDxCA,cAAwB,WAAA,eACxB,eAAwB,WAAA,gBACxB,gBAAwB,WAAA,kBpDsCxB,yBoDxCA,cAAwB,WAAA,eACxB,eAAwB,WAAA,gBACxB,gBAAwB,WAAA,kBpDsCxB,yBoDxCA,cAAwB,WAAA,eACxB,eAAwB,WAAA,gBACxB,gBAAwB,WAAA,kBpDsCxB,0BoDxCA,cAAwB,WAAA,eACxB,eAAwB,WAAA,gBACxB,gBAAwB,WAAA,kBAM5B,gBAAmB,eAAA,oBACnB,gBAAmB,eAAA,oBACnB,iBAAmB,eAAA,qBAInB,oBAAsB,YAAA,IACtB,kBAAsB,YAAA,IACtB,aAAsB,WAAA,OAItB,YAAc,MAAA,eEjCZ,cACE,MAAA,kBhEkBA,qBAAA,qBgEdE,MAAA,kBALJ,gBACE,MAAA,kBhEkBA,uBAAA,uBgEdE,MAAA,kBALJ,cACE,MAAA,kBhEkBA,qBAAA,qBgEdE,MAAA,kBALJ,WACE,MAAA,kBhEkBA,kBAAA,kBgEdE,MAAA,kBALJ,cACE,MAAA,kBhEkBA,qBAAA,qBgEdE,MAAA,kBALJ,aACE,MAAA,kBhEkBA,oBAAA,oBgEdE,MAAA,kBALJ,YACE,MAAA,kBhEkBA,mBAAA,mBgEdE,MAAA,kBALJ,WACE,MAAA,kBhEkBA,kBAAA,kBgEdE,MAAA,kBFkCN,YAAc,MAAA,kBAId,WG5CE,KAAA,CAAA,CAAA,EAAA,EACA,MAAA,YACA,YAAA,KACA,iBAAA,YACA,OAAA,ECFF,SCDE,WAAA,kBDKF,WCLE,WAAA"} \ No newline at end of file
diff --git a/library/bootstrap/js/bootstrap.js b/library/bootstrap/js/bootstrap.js
index 8c4a2f67c..086ba45b6 100644
--- a/library/bootstrap/js/bootstrap.js
+++ b/library/bootstrap/js/bootstrap.js
@@ -50,9 +50,10 @@ var Util = function ($) {
MozTransition: 'transitionend',
OTransition: 'oTransitionEnd otransitionend',
transition: 'transitionend'
+ };
- // shoutout AngusCroll (https://goo.gl/pxwQGp)
- };function toType(obj) {
+ // shoutout AngusCroll (https://goo.gl/pxwQGp)
+ function toType(obj) {
return {}.toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
}
@@ -66,8 +67,7 @@ var Util = function ($) {
delegateType: transition.end,
handle: function handle(event) {
if ($(event.target).is(this)) {
- return event.handleObj.handler.apply(this, arguments // eslint-disable-line prefer-rest-params
- );
+ return event.handleObj.handler.apply(this, arguments); // eslint-disable-line prefer-rest-params
}
return undefined;
}
@@ -177,7 +177,7 @@ var Util = function ($) {
setTransitionEndSupport();
return Util;
-}(jQuery
+}(jQuery);
/**
* --------------------------------------------------------------------------
@@ -186,7 +186,7 @@ var Util = function ($) {
* --------------------------------------------------------------------------
*/
-);var Alert = function ($) {
+var Alert = function ($) {
/**
* ------------------------------------------------------------------------
@@ -216,14 +216,14 @@ var Util = function ($) {
ALERT: 'alert',
FADE: 'fade',
SHOW: 'show'
+ };
- /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
- */
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
- };
var Alert = function () {
function Alert(element) {
_classCallCheck(this, Alert);
@@ -340,7 +340,7 @@ var Util = function ($) {
* ------------------------------------------------------------------------
*/
- $(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert())
+ $(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert()));
/**
* ------------------------------------------------------------------------
@@ -348,7 +348,7 @@ var Util = function ($) {
* ------------------------------------------------------------------------
*/
- );$.fn[NAME] = Alert._jQueryInterface;
+ $.fn[NAME] = Alert._jQueryInterface;
$.fn[NAME].Constructor = Alert;
$.fn[NAME].noConflict = function () {
$.fn[NAME] = JQUERY_NO_CONFLICT;
@@ -356,7 +356,7 @@ var Util = function ($) {
};
return Alert;
-}(jQuery
+}(jQuery);
/**
* --------------------------------------------------------------------------
@@ -365,7 +365,7 @@ var Util = function ($) {
* --------------------------------------------------------------------------
*/
-);var Button = function ($) {
+var Button = function ($) {
/**
* ------------------------------------------------------------------------
@@ -397,14 +397,14 @@ var Util = function ($) {
var Event = {
CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY,
FOCUS_BLUR_DATA_API: 'focus' + EVENT_KEY + DATA_API_KEY + ' ' + ('blur' + EVENT_KEY + DATA_API_KEY)
+ };
- /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
- */
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
- };
var Button = function () {
function Button(element) {
_classCallCheck(this, Button);
@@ -510,7 +510,7 @@ var Util = function ($) {
}).on(Event.FOCUS_BLUR_DATA_API, Selector.DATA_TOGGLE_CARROT, function (event) {
var button = $(event.target).closest(Selector.BUTTON)[0];
$(button).toggleClass(ClassName.FOCUS, /^focus(in)?$/.test(event.type));
- }
+ });
/**
* ------------------------------------------------------------------------
@@ -518,7 +518,7 @@ var Util = function ($) {
* ------------------------------------------------------------------------
*/
- );$.fn[NAME] = Button._jQueryInterface;
+ $.fn[NAME] = Button._jQueryInterface;
$.fn[NAME].Constructor = Button;
$.fn[NAME].noConflict = function () {
$.fn[NAME] = JQUERY_NO_CONFLICT;
@@ -526,7 +526,7 @@ var Util = function ($) {
};
return Button;
-}(jQuery
+}(jQuery);
/**
* --------------------------------------------------------------------------
@@ -535,7 +535,7 @@ var Util = function ($) {
* --------------------------------------------------------------------------
*/
-);var Carousel = function ($) {
+var Carousel = function ($) {
/**
* ------------------------------------------------------------------------
@@ -607,14 +607,14 @@ var Util = function ($) {
INDICATORS: '.carousel-indicators',
DATA_SLIDE: '[data-slide], [data-slide-to]',
DATA_RIDE: '[data-ride="carousel"]'
+ };
- /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
- */
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
- };
var Carousel = function () {
function Carousel(element, config) {
_classCallCheck(this, Carousel);
@@ -1017,7 +1017,7 @@ var Util = function ($) {
var $carousel = $(this);
Carousel._jQueryInterface.call($carousel, $carousel.data());
});
- }
+ });
/**
* ------------------------------------------------------------------------
@@ -1025,7 +1025,7 @@ var Util = function ($) {
* ------------------------------------------------------------------------
*/
- );$.fn[NAME] = Carousel._jQueryInterface;
+ $.fn[NAME] = Carousel._jQueryInterface;
$.fn[NAME].Constructor = Carousel;
$.fn[NAME].noConflict = function () {
$.fn[NAME] = JQUERY_NO_CONFLICT;
@@ -1033,7 +1033,7 @@ var Util = function ($) {
};
return Carousel;
-}(jQuery
+}(jQuery);
/**
* --------------------------------------------------------------------------
@@ -1042,7 +1042,7 @@ var Util = function ($) {
* --------------------------------------------------------------------------
*/
-);var Collapse = function ($) {
+var Collapse = function ($) {
/**
* ------------------------------------------------------------------------
@@ -1091,14 +1091,14 @@ var Util = function ($) {
var Selector = {
ACTIVES: '.show, .collapsing',
DATA_TOGGLE: '[data-toggle="collapse"]'
+ };
- /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
- */
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
- };
var Collapse = function () {
function Collapse(element, config) {
_classCallCheck(this, Collapse);
@@ -1280,8 +1280,8 @@ var Util = function ($) {
Collapse.prototype._getConfig = function _getConfig(config) {
config = $.extend({}, Default, config);
- config.toggle = Boolean(config.toggle // coerce string values
- );Util.typeCheckConfig(NAME, config, DefaultType);
+ config.toggle = Boolean(config.toggle); // coerce string values
+ Util.typeCheckConfig(NAME, config, DefaultType);
return config;
};
@@ -1378,7 +1378,7 @@ var Util = function ($) {
var config = data ? 'toggle' : $trigger.data();
Collapse._jQueryInterface.call($target, config);
});
- }
+ });
/**
* ------------------------------------------------------------------------
@@ -1386,7 +1386,7 @@ var Util = function ($) {
* ------------------------------------------------------------------------
*/
- );$.fn[NAME] = Collapse._jQueryInterface;
+ $.fn[NAME] = Collapse._jQueryInterface;
$.fn[NAME].Constructor = Collapse;
$.fn[NAME].noConflict = function () {
$.fn[NAME] = JQUERY_NO_CONFLICT;
@@ -1394,7 +1394,7 @@ var Util = function ($) {
};
return Collapse;
-}(jQuery
+}(jQuery);
/* global Popper */
@@ -1405,7 +1405,7 @@ var Util = function ($) {
* --------------------------------------------------------------------------
*/
-);var Dropdown = function ($) {
+var Dropdown = function ($) {
/**
* Check for Popper dependency
@@ -1479,14 +1479,14 @@ var Util = function ($) {
placement: 'string',
offset: '(number|string)',
flip: 'boolean'
+ };
- /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
- */
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
- };
var Dropdown = function () {
function Dropdown(element, config) {
_classCallCheck(this, Dropdown);
@@ -1812,7 +1812,7 @@ var Util = function ($) {
Dropdown._jQueryInterface.call($(this), 'toggle');
}).on(Event.CLICK_DATA_API, Selector.FORM_CHILD, function (e) {
e.stopPropagation();
- }
+ });
/**
* ------------------------------------------------------------------------
@@ -1820,7 +1820,7 @@ var Util = function ($) {
* ------------------------------------------------------------------------
*/
- );$.fn[NAME] = Dropdown._jQueryInterface;
+ $.fn[NAME] = Dropdown._jQueryInterface;
$.fn[NAME].Constructor = Dropdown;
$.fn[NAME].noConflict = function () {
$.fn[NAME] = JQUERY_NO_CONFLICT;
@@ -1828,7 +1828,7 @@ var Util = function ($) {
};
return Dropdown;
-}(jQuery
+}(jQuery);
/**
* --------------------------------------------------------------------------
@@ -1837,7 +1837,7 @@ var Util = function ($) {
* --------------------------------------------------------------------------
*/
-);var Modal = function ($) {
+var Modal = function ($) {
/**
* ------------------------------------------------------------------------
@@ -1897,14 +1897,14 @@ var Util = function ($) {
DATA_DISMISS: '[data-dismiss="modal"]',
FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top',
NAVBAR_TOGGLER: '.navbar-toggler'
+ };
- /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
- */
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
- };
var Modal = function () {
function Modal(element, config) {
_classCallCheck(this, Modal);
@@ -2096,8 +2096,8 @@ var Util = function ($) {
Modal.prototype._enforceFocus = function _enforceFocus() {
var _this14 = this;
- $(document).off(Event.FOCUSIN // guard against infinite focus loop
- ).on(Event.FOCUSIN, function (event) {
+ $(document).off(Event.FOCUSIN) // guard against infinite focus loop
+ .on(Event.FOCUSIN, function (event) {
if (document !== event.target && _this14._element !== event.target && !$(_this14._element).has(event.target).length) {
_this14._element.focus();
}
@@ -2259,17 +2259,17 @@ var Util = function ($) {
var actualPadding = $(element)[0].style.paddingRight;
var calculatedPadding = $(element).css('padding-right');
$(element).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + _this19._scrollbarWidth + 'px');
- }
+ });
// Adjust navbar-toggler margin
- );$(Selector.NAVBAR_TOGGLER).each(function (index, element) {
+ $(Selector.NAVBAR_TOGGLER).each(function (index, element) {
var actualMargin = $(element)[0].style.marginRight;
var calculatedMargin = $(element).css('margin-right');
$(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) + _this19._scrollbarWidth + 'px');
- }
+ });
// Adjust body padding
- );var actualPadding = document.body.style.paddingRight;
+ var actualPadding = document.body.style.paddingRight;
var calculatedPadding = $('body').css('padding-right');
$('body').data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + this._scrollbarWidth + 'px');
}
@@ -2282,18 +2282,18 @@ var Util = function ($) {
if (typeof padding !== 'undefined') {
$(element).css('padding-right', padding).removeData('padding-right');
}
- }
+ });
// Restore navbar-toggler margin
- );$(Selector.NAVBAR_TOGGLER).each(function (index, element) {
+ $(Selector.NAVBAR_TOGGLER).each(function (index, element) {
var margin = $(element).data('margin-right');
if (typeof margin !== 'undefined') {
$(element).css('margin-right', margin).removeData('margin-right');
}
- }
+ });
// Restore body padding
- );var padding = $('body').data('padding-right');
+ var padding = $('body').data('padding-right');
if (typeof padding !== 'undefined') {
$('body').css('padding-right', padding).removeData('padding-right');
}
@@ -2383,7 +2383,7 @@ var Util = function ($) {
});
Modal._jQueryInterface.call($(target), config, this);
- }
+ });
/**
* ------------------------------------------------------------------------
@@ -2391,7 +2391,7 @@ var Util = function ($) {
* ------------------------------------------------------------------------
*/
- );$.fn[NAME] = Modal._jQueryInterface;
+ $.fn[NAME] = Modal._jQueryInterface;
$.fn[NAME].Constructor = Modal;
$.fn[NAME].noConflict = function () {
$.fn[NAME] = JQUERY_NO_CONFLICT;
@@ -2399,7 +2399,7 @@ var Util = function ($) {
};
return Modal;
-}(jQuery
+}(jQuery);
/**
* --------------------------------------------------------------------------
@@ -2408,7 +2408,7 @@ var Util = function ($) {
* --------------------------------------------------------------------------
*/
-);var ScrollSpy = function ($) {
+var ScrollSpy = function ($) {
/**
* ------------------------------------------------------------------------
@@ -2461,14 +2461,14 @@ var Util = function ($) {
var OffsetMethod = {
OFFSET: 'offset',
POSITION: 'position'
+ };
- /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
- */
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
- };
var ScrollSpy = function () {
function ScrollSpy(element, config) {
var _this21 = this;
@@ -2633,10 +2633,10 @@ var Util = function ($) {
$link.addClass(ClassName.ACTIVE);
} else {
// Set triggered link as active
- $link.addClass(ClassName.ACTIVE
+ $link.addClass(ClassName.ACTIVE);
// Set triggered links parents as active
// With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
- );$link.parents(Selector.NAV_LIST_GROUP).prev(Selector.NAV_LINKS + ', ' + Selector.LIST_ITEMS).addClass(ClassName.ACTIVE);
+ $link.parents(Selector.NAV_LIST_GROUP).prev(Selector.NAV_LINKS + ', ' + Selector.LIST_ITEMS).addClass(ClassName.ACTIVE);
}
$(this._scrollElement).trigger(Event.ACTIVATE, {
@@ -2697,7 +2697,7 @@ var Util = function ($) {
var $spy = $(scrollSpys[i]);
ScrollSpy._jQueryInterface.call($spy, $spy.data());
}
- }
+ });
/**
* ------------------------------------------------------------------------
@@ -2705,7 +2705,7 @@ var Util = function ($) {
* ------------------------------------------------------------------------
*/
- );$.fn[NAME] = ScrollSpy._jQueryInterface;
+ $.fn[NAME] = ScrollSpy._jQueryInterface;
$.fn[NAME].Constructor = ScrollSpy;
$.fn[NAME].noConflict = function () {
$.fn[NAME] = JQUERY_NO_CONFLICT;
@@ -2713,7 +2713,7 @@ var Util = function ($) {
};
return ScrollSpy;
-}(jQuery
+}(jQuery);
/**
* --------------------------------------------------------------------------
@@ -2722,7 +2722,7 @@ var Util = function ($) {
* --------------------------------------------------------------------------
*/
-);var Tab = function ($) {
+var Tab = function ($) {
/**
* ------------------------------------------------------------------------
@@ -2761,14 +2761,14 @@ var Util = function ($) {
DATA_TOGGLE: '[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',
DROPDOWN_TOGGLE: '.dropdown-toggle',
DROPDOWN_ACTIVE_CHILD: '> .dropdown-menu .active'
+ };
- /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
- */
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
- };
var Tab = function () {
function Tab(element) {
_classCallCheck(this, Tab);
@@ -2947,7 +2947,7 @@ var Util = function ($) {
$(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
event.preventDefault();
Tab._jQueryInterface.call($(this), 'show');
- }
+ });
/**
* ------------------------------------------------------------------------
@@ -2955,7 +2955,7 @@ var Util = function ($) {
* ------------------------------------------------------------------------
*/
- );$.fn[NAME] = Tab._jQueryInterface;
+ $.fn[NAME] = Tab._jQueryInterface;
$.fn[NAME].Constructor = Tab;
$.fn[NAME].noConflict = function () {
$.fn[NAME] = JQUERY_NO_CONFLICT;
@@ -2963,7 +2963,7 @@ var Util = function ($) {
};
return Tab;
-}(jQuery
+}(jQuery);
/* global Popper */
@@ -2974,7 +2974,7 @@ var Util = function ($) {
* --------------------------------------------------------------------------
*/
-);var Tooltip = function ($) {
+var Tooltip = function ($) {
/**
* Check for Popper dependency
@@ -3069,14 +3069,14 @@ var Util = function ($) {
FOCUS: 'focus',
CLICK: 'click',
MANUAL: 'manual'
+ };
- /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
- */
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
- };
var Tooltip = function () {
function Tooltip(element, config) {
_classCallCheck(this, Tooltip);
@@ -3233,13 +3233,13 @@ var Util = function ($) {
}
});
- $(tip).addClass(ClassName.SHOW
+ $(tip).addClass(ClassName.SHOW);
// if this is a touch-enabled device we add extra
// empty mouseover listeners to the body's immediate children;
// only needed because of broken event delegation on iOS
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
- );if ('ontouchstart' in document.documentElement) {
+ if ('ontouchstart' in document.documentElement) {
$('body').children().on('mouseover', null, $.noop);
}
@@ -3293,11 +3293,11 @@ var Util = function ($) {
return;
}
- $(tip).removeClass(ClassName.SHOW
+ $(tip).removeClass(ClassName.SHOW);
// if this is a touch-enabled device we remove the extra
// empty mouseover listeners we added for iOS support
- );if ('ontouchstart' in document.documentElement) {
+ if ('ontouchstart' in document.documentElement) {
$('body').children().off('mouseover', null, $.noop);
}
@@ -3638,7 +3638,7 @@ var Util = function ($) {
};
return Tooltip;
-}(jQuery
+}(jQuery);
/**
* --------------------------------------------------------------------------
@@ -3647,7 +3647,7 @@ var Util = function ($) {
* --------------------------------------------------------------------------
*/
-);var Popover = function ($) {
+var Popover = function ($) {
/**
* ------------------------------------------------------------------------
@@ -3695,14 +3695,14 @@ var Util = function ($) {
FOCUSOUT: 'focusout' + EVENT_KEY,
MOUSEENTER: 'mouseenter' + EVENT_KEY,
MOUSELEAVE: 'mouseleave' + EVENT_KEY
+ };
- /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
- */
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
- };
var Popover = function (_Tooltip) {
_inherits(Popover, _Tooltip);
@@ -3727,10 +3727,10 @@ var Util = function ($) {
};
Popover.prototype.setContent = function setContent() {
- var $tip = $(this.getTipElement()
+ var $tip = $(this.getTipElement());
// we use append for html objects to maintain js events
- );this.setElementContent($tip.find(Selector.TITLE), this.getTitle());
+ this.setElementContent($tip.find(Selector.TITLE), this.getTitle());
this.setElementContent($tip.find(Selector.CONTENT), this._getContent());
$tip.removeClass(ClassName.FADE + ' ' + ClassName.SHOW);
diff --git a/library/oauth2/.gitignore b/library/oauth2/.gitignore
deleted file mode 100644
index c43a667d4..000000000
--- a/library/oauth2/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-# Test Files #
-test/config/test.sqlite
-vendor
-composer.lock
-.idea
diff --git a/library/oauth2/.travis.yml b/library/oauth2/.travis.yml
deleted file mode 100644
index dd4aae4a6..000000000
--- a/library/oauth2/.travis.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-language: php
-sudo: false
-cache:
- directories:
- - $HOME/.composer/cache
- - vendor
-php:
-- 5.3
-- 5.4
-- 5.5
-- 5.6
-- 7
-- hhvm
-env:
- global:
- - SKIP_MONGO_TESTS=1
- - secure: Bc5ZqvZ1YYpoPZNNuU2eCB8DS6vBYrAdfBtTenBs5NSxzb+Vjven4kWakbzaMvZjb/Ib7Uph7DGuOtJXpmxnvBXPLd707LZ89oFWN/yqQlZKCcm8iErvJCB5XL+/ONHj2iPdR242HJweMcat6bMCwbVWoNDidjtWMH0U2mYFy3M=
- - secure: R3bXlymyFiY2k2jf7+fv/J8i34wtXTkmD4mCr5Ps/U+vn9axm2VtvR2Nj+r7LbRjn61gzFE/xIVjYft/wOyBOYwysrfriydrnRVS0owh6y+7EyOyQWbRX11vVQMf8o31QCQE5BY58V5AJZW3MjoOL0FVlTgySJiJvdw6Pv18v+E=
-services:
-- mongodb
-- redis-server
-- cassandra
-before_install:
-- phpenv config-rm xdebug.ini || return 0
-install:
-- composer install --no-interaction
-before_script:
-- psql -c 'create database oauth2_server_php;' -U postgres
-after_script:
-- php test/cleanup.php
diff --git a/library/oauth2/CHANGELOG.md b/library/oauth2/CHANGELOG.md
deleted file mode 100644
index 03d925e06..000000000
--- a/library/oauth2/CHANGELOG.md
+++ /dev/null
@@ -1,152 +0,0 @@
-CHANGELOG for 1.x
-=================
-
-This changelog references the relevant changes (bug and security fixes) done
-in 1.x minor versions.
-
-To see the files changed for a given bug, go to https://github.com/bshaffer/oauth2-server-php/issues/### where ### is the bug number
-To get the diff between two versions, go to https://github.com/bshaffer/oauth2-server-php/compare/v1.0...v1.1
-To get the diff for a specific change, go to https://github.com/bshaffer/oauth2-server-php/commit/XXX where XXX is the change hash
-
-* 1.8.0 (2015-09-18)
-
- PR: https://github.com/bshaffer/oauth2-server-php/pull/643
-
- * bug #594 - adds jti
- * bug #598 - fixes lifetime configurations for JWTs
- * bug #634 - fixes travis builds, upgrade to containers
- * bug #586 - support for revoking tokens
- * bug #636 - Adds FirebaseJWT bridge
- * bug #639 - Mongo HHVM compatibility
-
-* 1.7.0 (2015-04-23)
-
- PR: https://github.com/bshaffer/oauth2-server-php/pull/572
-
- * bug #500 - PDO fetch mode changed from FETCH_BOTH to FETCH_ASSOC
- * bug #508 - Case insensitive for Bearer token header name ba716d4
- * bug #512 - validateRedirectUri is now public
- * bug #530 - Add PublicKeyInterface, UserClaimsInterface to Cassandra Storage
- * bug #505 - DynamoDB storage fixes
- * bug #556 - adds "code id_token" return type to openid connect
- * bug #563 - Include "issuer" config key for JwtAccessToken
- * bug #564 - Fixes JWT vulnerability
- * bug #571 - Added unset_refresh_token_after_use option
-
-* 1.6 (2015-01-16)
-
- PR: https://github.com/bshaffer/oauth2-server-php/pull/496
-
- * bug 437 - renames CryptoToken to JwtAccessToken / use_crypto_tokens to use_jwt_access_tokens
- * bug 447 - Adds a Couchbase storage implementation
- * bug 460 - Rename JWT claims to match spec
- * bug 470 - order does not matter for multi-valued response types
- * bug 471 - Make validateAuthorizeRequest available for POST in addition to GET
- * bug 475 - Adds JTI table definitiion
- * bug 481 - better randomness for generating access tokens
- * bug 480 - Use hash_equals() for signature verification (prevents remote timing attacks)
- * bugs 489, 491, 498 - misc other fixes
-
-* 1.5 (2014-08-27)
-
- PR: https://github.com/bshaffer/oauth2-server-php/pull/446
-
- * bug #399 - Add DynamoDB Support
- * bug #404 - renamed error name for malformed/expired tokens
- * bug #412 - Openid connect: fixes for claims with more than one scope / Add support for the prompt parameter ('consent' and 'none')
- * bug #411 - fixes xml output
- * bug #413 - fixes invalid format error
- * bug #401 - fixes code standards / whitespace
- * bug #354 - bundles PDO SQL with the library
- * [BC] bug #397 - refresh tokens should not be encrypted
- * bug #423 - makes "scope" optional for refresh token storage
-
-* 1.4 (2014-06-12)
-
- PR: https://github.com/bshaffer/oauth2-server-php/pull/392
-
- * bug #189 Storage\PDO - allows DSN string in constructor
- * bug #233 Bearer Tokens - allows token in request body for PUT requests
- * bug #346 Fixes open_basedir warning
- * bug #351 Adds OpenID Connect support
- * bug #355 Adds php 5.6 and HHVM to travis.ci testing
- * [BC] bug #358 Adds `getQuerystringIdentifier()` to the GrantType interface
- * bug #363 Encryption\JWT - Allows for subclassing JWT Headers
- * bug #349 Bearer Tokens - adds requestHasToken method for when access tokens are optional
- * bug #301 Encryption\JWT - fixes urlSafeB64Encode(): ensures newlines are replaced as expected
- * bug #323 ResourceController - client_id is no longer required to be returned when calling getAccessToken
- * bug #367 Storage\PDO - adds Postgres support
- * bug #368 Access Tokens - use mcrypt_create_iv or openssl_random_pseudo_bytes to create token string
- * bug #376 Request - allows case insensitive headers
- * bug #384 Storage\PDO - can pass in PDO options in constructor of PDO storage
- * misc fixes #361, #292, #373, #374, #379, #396
-* 1.3 (2014-02-27)
-
- PR: https://github.com/bshaffer/oauth2-server-php/pull/325
-
- * bug #311 adds cassandra storage
- * bug #298 fixes response code for user credentials grant type
- * bug #318 adds 'use_crypto_tokens' config to Server class for better DX
- * [BC] bug #320 pass client_id to getDefaultScope
- * bug #324 better feedback when running tests
- * bug #335 adds support for non-expiring refresh tokens
- * bug #333 fixes Pdo storage for getClientKey
- * bug #336 fixes Redis storage for expireAuthorizationCode
-
-* 1.2 (2014-01-03)
-
- PR: https://github.com/bshaffer/oauth2-server-php/pull/288
-
- * bug #285 changed response header from 200 to 401 when empty token received
- * bug #286 adds documentation and links to spec for not including error messages when no token is supplied
- * bug #280 ensures PHP warnings do not get thrown as a result of an invalid argument to $jwt->decode()
- * bug #279 predis wrong number of arguments
- * bug #277 Securing JS WebApp client secret w/ password grant type
-
-* 1.1 (2013-12-17)
-
- PR: https://github.com/bshaffer/oauth2-server-php/pull/276
-
- * bug #278 adds refresh token configuration to Server class
- * bug #274 Supplying a null client_id and client_secret grants API access
- * bug #244 [MongoStorage] More detailed implementation info
- * bug #268 Implement jti for JWT Bearer tokens to prevent replay attacks.
- * bug #266 Removing unused argument to getAccessTokenData
- * bug #247 Make Bearer token type consistent
- * bug #253 Fixing CryptoToken refresh token lifetime
- * bug #246 refactors public key logic to be more intuitive
- * bug #245 adds support for JSON crypto tokens
- * bug #230 Remove unused columns in oauth_clients
- * bug #215 makes Redis Scope Storage obey the same paradigm as PDO
- * bug #228 removes scope group
- * bug #227 squelches open basedir restriction error
- * bug #223 Updated docblocks for RefreshTokenInterface.php
- * bug #224 Adds protected properties
- * bug #217 Implement ScopeInterface for PDO, Redis
-
-* 1.0 (2013-08-12)
-
- * bug #203 Add redirect\_status_code config param for AuthorizeController
- * bug #205 ensures unnecessary ? is not set when ** bug
- * bug #204 Fixed call to LogicException
- * bug #202 Add explode to checkRestrictedGrant in PDO Storage
- * bug #197 adds support for 'false' default scope ** bug
- * bug #192 reference errors and adds tests
- * bug #194 makes some appropriate properties ** bug
- * bug #191 passes config to HttpBasic
- * bug #190 validates client credentials before ** bug
- * bug #171 Fix wrong redirect following authorization step
- * bug #187 client_id is now passed to getDefaultScope().
- * bug #176 Require refresh_token in getRefreshToken response
- * bug #174 make user\_id not required for refresh_token grant
- * bug #173 Duplication in JwtBearer Grant
- * bug #168 user\_id not required for authorization_code grant
- * bug #133 hardens default security for user object
- * bug #163 allows redirect\_uri on authorization_code to be NULL in docs example
- * bug #162 adds getToken on ResourceController for convenience
- * bug #161 fixes fatal error
- * bug #163 Invalid redirect_uri handling
- * bug #156 user\_id in OAuth2\_Storage_AuthorizationCodeInterface::getAuthorizationCode() response
- * bug #157 Fix for extending access and refresh tokens
- * bug #154 ResponseInterface: getParameter method is used in the library but not defined in the interface
- * bug #148 Add more detail to examples in Readme.md
diff --git a/library/oauth2/LICENSE b/library/oauth2/LICENSE
deleted file mode 100644
index d7ece8467..000000000
--- a/library/oauth2/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License
-
-Copyright (c) 2014 Brent Shaffer
-
-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.
diff --git a/library/oauth2/README.md b/library/oauth2/README.md
deleted file mode 100644
index 4ceda6cf9..000000000
--- a/library/oauth2/README.md
+++ /dev/null
@@ -1,8 +0,0 @@
-oauth2-server-php
-=================
-
-[![Build Status](https://travis-ci.org/bshaffer/oauth2-server-php.svg?branch=develop)](https://travis-ci.org/bshaffer/oauth2-server-php)
-
-[![Total Downloads](https://poser.pugx.org/bshaffer/oauth2-server-php/downloads.png)](https://packagist.org/packages/bshaffer/oauth2-server-php)
-
-View the [complete documentation](http://bshaffer.github.io/oauth2-server-php-docs/) \ No newline at end of file
diff --git a/library/oauth2/phpunit.xml b/library/oauth2/phpunit.xml
deleted file mode 100644
index e36403f0a..000000000
--- a/library/oauth2/phpunit.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<phpunit backupGlobals="false"
- backupStaticAttributes="false"
- colors="true"
- convertErrorsToExceptions="true"
- convertNoticesToExceptions="true"
- convertWarningsToExceptions="true"
- processIsolation="false"
- stopOnFailure="false"
- syntaxCheck="false"
- bootstrap="test/bootstrap.php"
->
- <testsuites>
- <testsuite name="Oauth2 Test Suite">
- <directory>./test/OAuth2/</directory>
- </testsuite>
- </testsuites>
-
- <filter>
- <whitelist>
- <directory suffix=".php">./src/OAuth2/</directory>
- </whitelist>
- </filter>
-</phpunit>
diff --git a/library/oauth2/src/OAuth2/Autoloader.php b/library/oauth2/src/OAuth2/Autoloader.php
deleted file mode 100644
index ecfb6ba75..000000000
--- a/library/oauth2/src/OAuth2/Autoloader.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-
-namespace OAuth2;
-
-/**
- * Autoloads OAuth2 classes
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- * @license MIT License
- */
-class Autoloader
-{
- private $dir;
-
- public function __construct($dir = null)
- {
- if (is_null($dir)) {
- $dir = dirname(__FILE__).'/..';
- }
- $this->dir = $dir;
- }
- /**
- * Registers OAuth2\Autoloader as an SPL autoloader.
- */
- public static function register($dir = null)
- {
- ini_set('unserialize_callback_func', 'spl_autoload_call');
- spl_autoload_register(array(new self($dir), 'autoload'));
- }
-
- /**
- * Handles autoloading of classes.
- *
- * @param string $class A class name.
- *
- * @return boolean Returns true if the class has been loaded
- */
- public function autoload($class)
- {
- if (0 !== strpos($class, 'OAuth2')) {
- return;
- }
-
- if (file_exists($file = $this->dir.'/'.str_replace('\\', '/', $class).'.php')) {
- require $file;
- }
- }
-}
diff --git a/library/oauth2/src/OAuth2/ClientAssertionType/ClientAssertionTypeInterface.php b/library/oauth2/src/OAuth2/ClientAssertionType/ClientAssertionTypeInterface.php
deleted file mode 100644
index 29c7171b5..000000000
--- a/library/oauth2/src/OAuth2/ClientAssertionType/ClientAssertionTypeInterface.php
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-
-namespace OAuth2\ClientAssertionType;
-
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-
-/**
- * Interface for all OAuth2 Client Assertion Types
- */
-interface ClientAssertionTypeInterface
-{
- public function validateRequest(RequestInterface $request, ResponseInterface $response);
- public function getClientId();
-}
diff --git a/library/oauth2/src/OAuth2/ClientAssertionType/HttpBasic.php b/library/oauth2/src/OAuth2/ClientAssertionType/HttpBasic.php
deleted file mode 100644
index 0ecb7e18d..000000000
--- a/library/oauth2/src/OAuth2/ClientAssertionType/HttpBasic.php
+++ /dev/null
@@ -1,123 +0,0 @@
-<?php
-
-namespace OAuth2\ClientAssertionType;
-
-use OAuth2\Storage\ClientCredentialsInterface;
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-
-/**
- * Validate a client via Http Basic authentication
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-class HttpBasic implements ClientAssertionTypeInterface
-{
- private $clientData;
-
- protected $storage;
- protected $config;
-
- /**
- * @param OAuth2\Storage\ClientCredentialsInterface $clientStorage REQUIRED Storage class for retrieving client credentials information
- * @param array $config OPTIONAL Configuration options for the server
- * <code>
- * $config = array(
- * 'allow_credentials_in_request_body' => true, // whether to look for credentials in the POST body in addition to the Authorize HTTP Header
- * 'allow_public_clients' => true // if true, "public clients" (clients without a secret) may be authenticated
- * );
- * </code>
- */
- public function __construct(ClientCredentialsInterface $storage, array $config = array())
- {
- $this->storage = $storage;
- $this->config = array_merge(array(
- 'allow_credentials_in_request_body' => true,
- 'allow_public_clients' => true,
- ), $config);
- }
-
- public function validateRequest(RequestInterface $request, ResponseInterface $response)
- {
- if (!$clientData = $this->getClientCredentials($request, $response)) {
- return false;
- }
-
- if (!isset($clientData['client_id'])) {
- throw new \LogicException('the clientData array must have "client_id" set');
- }
-
- if (!isset($clientData['client_secret']) || $clientData['client_secret'] == '') {
- if (!$this->config['allow_public_clients']) {
- $response->setError(400, 'invalid_client', 'client credentials are required');
-
- return false;
- }
-
- if (!$this->storage->isPublicClient($clientData['client_id'])) {
- $response->setError(400, 'invalid_client', 'This client is invalid or must authenticate using a client secret');
-
- return false;
- }
- } elseif ($this->storage->checkClientCredentials($clientData['client_id'], $clientData['client_secret']) === false) {
- $response->setError(400, 'invalid_client', 'The client credentials are invalid');
-
- return false;
- }
-
- $this->clientData = $clientData;
-
- return true;
- }
-
- public function getClientId()
- {
- return $this->clientData['client_id'];
- }
-
- /**
- * Internal function used to get the client credentials from HTTP basic
- * auth or POST data.
- *
- * According to the spec (draft 20), the client_id can be provided in
- * the Basic Authorization header (recommended) or via GET/POST.
- *
- * @return
- * A list containing the client identifier and password, for example
- * @code
- * return array(
- * "client_id" => CLIENT_ID, // REQUIRED the client id
- * "client_secret" => CLIENT_SECRET, // OPTIONAL the client secret (may be omitted for public clients)
- * );
- * @endcode
- *
- * @see http://tools.ietf.org/html/rfc6749#section-2.3.1
- *
- * @ingroup oauth2_section_2
- */
- public function getClientCredentials(RequestInterface $request, ResponseInterface $response = null)
- {
- if (!is_null($request->headers('PHP_AUTH_USER')) && !is_null($request->headers('PHP_AUTH_PW'))) {
- return array('client_id' => $request->headers('PHP_AUTH_USER'), 'client_secret' => $request->headers('PHP_AUTH_PW'));
- }
-
- if ($this->config['allow_credentials_in_request_body']) {
- // Using POST for HttpBasic authorization is not recommended, but is supported by specification
- if (!is_null($request->request('client_id'))) {
- /**
- * client_secret can be null if the client's password is an empty string
- * @see http://tools.ietf.org/html/rfc6749#section-2.3.1
- */
-
- return array('client_id' => $request->request('client_id'), 'client_secret' => $request->request('client_secret'));
- }
- }
-
- if ($response) {
- $message = $this->config['allow_credentials_in_request_body'] ? ' or body' : '';
- $response->setError(400, 'invalid_client', 'Client credentials were not found in the headers'.$message);
- }
-
- return null;
- }
-}
diff --git a/library/oauth2/src/OAuth2/Controller/AuthorizeController.php b/library/oauth2/src/OAuth2/Controller/AuthorizeController.php
deleted file mode 100644
index a9a722587..000000000
--- a/library/oauth2/src/OAuth2/Controller/AuthorizeController.php
+++ /dev/null
@@ -1,388 +0,0 @@
-<?php
-
-namespace OAuth2\Controller;
-
-use OAuth2\Storage\ClientInterface;
-use OAuth2\ScopeInterface;
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-use OAuth2\Scope;
-
-/**
- * @see OAuth2\Controller\AuthorizeControllerInterface
- */
-class AuthorizeController implements AuthorizeControllerInterface
-{
- private $scope;
- private $state;
- private $client_id;
- private $redirect_uri;
- private $response_type;
-
- protected $clientStorage;
- protected $responseTypes;
- protected $config;
- protected $scopeUtil;
-
- /**
- * @param OAuth2\Storage\ClientInterface $clientStorage REQUIRED Instance of OAuth2\Storage\ClientInterface to retrieve client information
- * @param array $responseTypes OPTIONAL Array of OAuth2\ResponseType\ResponseTypeInterface objects. Valid array
- * keys are "code" and "token"
- * @param array $config OPTIONAL Configuration options for the server
- * <code>
- * $config = array(
- * 'allow_implicit' => false, // if the controller should allow the "implicit" grant type
- * 'enforce_state' => true // if the controller should require the "state" parameter
- * 'require_exact_redirect_uri' => true, // if the controller should require an exact match on the "redirect_uri" parameter
- * 'redirect_status_code' => 302, // HTTP status code to use for redirect responses
- * );
- * </code>
- * @param OAuth2\ScopeInterface $scopeUtil OPTIONAL Instance of OAuth2\ScopeInterface to validate the requested scope
- */
- public function __construct(ClientInterface $clientStorage, array $responseTypes = array(), array $config = array(), ScopeInterface $scopeUtil = null)
- {
- $this->clientStorage = $clientStorage;
- $this->responseTypes = $responseTypes;
- $this->config = array_merge(array(
- 'allow_implicit' => false,
- 'enforce_state' => true,
- 'require_exact_redirect_uri' => true,
- 'redirect_status_code' => 302,
- ), $config);
-
- if (is_null($scopeUtil)) {
- $scopeUtil = new Scope();
- }
- $this->scopeUtil = $scopeUtil;
- }
-
- public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null)
- {
- if (!is_bool($is_authorized)) {
- throw new \InvalidArgumentException('Argument "is_authorized" must be a boolean. This method must know if the user has granted access to the client.');
- }
-
- // We repeat this, because we need to re-validate. The request could be POSTed
- // by a 3rd-party (because we are not internally enforcing NONCEs, etc)
- if (!$this->validateAuthorizeRequest($request, $response)) {
- return;
- }
-
- // If no redirect_uri is passed in the request, use client's registered one
- if (empty($this->redirect_uri)) {
- $clientData = $this->clientStorage->getClientDetails($this->client_id);
- $registered_redirect_uri = $clientData['redirect_uri'];
- }
-
- // the user declined access to the client's application
- if ($is_authorized === false) {
- $redirect_uri = $this->redirect_uri ?: $registered_redirect_uri;
- $this->setNotAuthorizedResponse($request, $response, $redirect_uri, $user_id);
-
- return;
- }
-
- // build the parameters to set in the redirect URI
- if (!$params = $this->buildAuthorizeParameters($request, $response, $user_id)) {
- return;
- }
-
- $authResult = $this->responseTypes[$this->response_type]->getAuthorizeResponse($params, $user_id);
-
- list($redirect_uri, $uri_params) = $authResult;
-
- if (empty($redirect_uri) && !empty($registered_redirect_uri)) {
- $redirect_uri = $registered_redirect_uri;
- }
-
- $uri = $this->buildUri($redirect_uri, $uri_params);
-
- // return redirect response
- $response->setRedirect($this->config['redirect_status_code'], $uri);
- }
-
- protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null)
- {
- $error = 'access_denied';
- $error_message = 'The user denied access to your application';
- $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->state, $error, $error_message);
- }
-
- /*
- * We have made this protected so this class can be extended to add/modify
- * these parameters
- */
- protected function buildAuthorizeParameters($request, $response, $user_id)
- {
- // @TODO: we should be explicit with this in the future
- $params = array(
- 'scope' => $this->scope,
- 'state' => $this->state,
- 'client_id' => $this->client_id,
- 'redirect_uri' => $this->redirect_uri,
- 'response_type' => $this->response_type,
- );
-
- return $params;
- }
-
- public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response)
- {
- // Make sure a valid client id was supplied (we can not redirect because we were unable to verify the URI)
- if (!$client_id = $request->query('client_id', $request->request('client_id'))) {
- // We don't have a good URI to use
- $response->setError(400, 'invalid_client', "No client id supplied");
-
- return false;
- }
-
- // Get client details
- if (!$clientData = $this->clientStorage->getClientDetails($client_id)) {
- $response->setError(400, 'invalid_client', 'The client id supplied is invalid');
-
- return false;
- }
-
- $registered_redirect_uri = isset($clientData['redirect_uri']) ? $clientData['redirect_uri'] : '';
-
- // Make sure a valid redirect_uri was supplied. If specified, it must match the clientData URI.
- // @see http://tools.ietf.org/html/rfc6749#section-3.1.2
- // @see http://tools.ietf.org/html/rfc6749#section-4.1.2.1
- // @see http://tools.ietf.org/html/rfc6749#section-4.2.2.1
- if ($supplied_redirect_uri = $request->query('redirect_uri', $request->request('redirect_uri'))) {
- // validate there is no fragment supplied
- $parts = parse_url($supplied_redirect_uri);
- if (isset($parts['fragment']) && $parts['fragment']) {
- $response->setError(400, 'invalid_uri', 'The redirect URI must not contain a fragment');
-
- return false;
- }
-
- // validate against the registered redirect uri(s) if available
- if ($registered_redirect_uri && !$this->validateRedirectUri($supplied_redirect_uri, $registered_redirect_uri)) {
- $response->setError(400, 'redirect_uri_mismatch', 'The redirect URI provided is missing or does not match', '#section-3.1.2');
-
- return false;
- }
- $redirect_uri = $supplied_redirect_uri;
- } else {
- // use the registered redirect_uri if none has been supplied, if possible
- if (!$registered_redirect_uri) {
- $response->setError(400, 'invalid_uri', 'No redirect URI was supplied or stored');
-
- return false;
- }
-
- if (count(explode(' ', $registered_redirect_uri)) > 1) {
- $response->setError(400, 'invalid_uri', 'A redirect URI must be supplied when multiple redirect URIs are registered', '#section-3.1.2.3');
-
- return false;
- }
- $redirect_uri = $registered_redirect_uri;
- }
-
- // Select the redirect URI
- $response_type = $request->query('response_type', $request->request('response_type'));
-
- // for multiple-valued response types - make them alphabetical
- if (false !== strpos($response_type, ' ')) {
- $types = explode(' ', $response_type);
- sort($types);
- $response_type = ltrim(implode(' ', $types));
- }
-
- $state = $request->query('state', $request->request('state'));
-
- // type and client_id are required
- if (!$response_type || !in_array($response_type, $this->getValidResponseTypes())) {
- $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_request', 'Invalid or missing response type', null);
-
- return false;
- }
-
- if ($response_type == self::RESPONSE_TYPE_AUTHORIZATION_CODE) {
- if (!isset($this->responseTypes['code'])) {
- $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unsupported_response_type', 'authorization code grant type not supported', null);
-
- return false;
- }
- if (!$this->clientStorage->checkRestrictedGrantType($client_id, 'authorization_code')) {
- $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unauthorized_client', 'The grant type is unauthorized for this client_id', null);
-
- return false;
- }
- if ($this->responseTypes['code']->enforceRedirect() && !$redirect_uri) {
- $response->setError(400, 'redirect_uri_mismatch', 'The redirect URI is mandatory and was not supplied');
-
- return false;
- }
- } else {
- if (!$this->config['allow_implicit']) {
- $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unsupported_response_type', 'implicit grant type not supported', null);
-
- return false;
- }
- if (!$this->clientStorage->checkRestrictedGrantType($client_id, 'implicit')) {
- $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unauthorized_client', 'The grant type is unauthorized for this client_id', null);
-
- return false;
- }
- }
-
- // validate requested scope if it exists
- $requestedScope = $this->scopeUtil->getScopeFromRequest($request);
-
- if ($requestedScope) {
- // restrict scope by client specific scope if applicable,
- // otherwise verify the scope exists
- $clientScope = $this->clientStorage->getClientScope($client_id);
- if ((empty($clientScope) && !$this->scopeUtil->scopeExists($requestedScope))
- || (!empty($clientScope) && !$this->scopeUtil->checkScope($requestedScope, $clientScope))) {
- $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_scope', 'An unsupported scope was requested', null);
-
- return false;
- }
- } else {
- // use a globally-defined default scope
- $defaultScope = $this->scopeUtil->getDefaultScope($client_id);
-
- if (false === $defaultScope) {
- $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_client', 'This application requires you specify a scope parameter', null);
-
- return false;
- }
-
- $requestedScope = $defaultScope;
- }
-
- // Validate state parameter exists (if configured to enforce this)
- if ($this->config['enforce_state'] && !$state) {
- $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, null, 'invalid_request', 'The state parameter is required');
-
- return false;
- }
-
- // save the input data and return true
- $this->scope = $requestedScope;
- $this->state = $state;
- $this->client_id = $client_id;
- // Only save the SUPPLIED redirect URI (@see http://tools.ietf.org/html/rfc6749#section-4.1.3)
- $this->redirect_uri = $supplied_redirect_uri;
- $this->response_type = $response_type;
-
- return true;
- }
-
- /**
- * Build the absolute URI based on supplied URI and parameters.
- *
- * @param $uri An absolute URI.
- * @param $params Parameters to be append as GET.
- *
- * @return
- * An absolute URI with supplied parameters.
- *
- * @ingroup oauth2_section_4
- */
- private function buildUri($uri, $params)
- {
- $parse_url = parse_url($uri);
-
- // Add our params to the parsed uri
- foreach ($params as $k => $v) {
- if (isset($parse_url[$k])) {
- $parse_url[$k] .= "&" . http_build_query($v, '', '&');
- } else {
- $parse_url[$k] = http_build_query($v, '', '&');
- }
- }
-
- // Put humpty dumpty back together
- return
- ((isset($parse_url["scheme"])) ? $parse_url["scheme"] . "://" : "")
- . ((isset($parse_url["user"])) ? $parse_url["user"]
- . ((isset($parse_url["pass"])) ? ":" . $parse_url["pass"] : "") . "@" : "")
- . ((isset($parse_url["host"])) ? $parse_url["host"] : "")
- . ((isset($parse_url["port"])) ? ":" . $parse_url["port"] : "")
- . ((isset($parse_url["path"])) ? $parse_url["path"] : "")
- . ((isset($parse_url["query"]) && !empty($parse_url['query'])) ? "?" . $parse_url["query"] : "")
- . ((isset($parse_url["fragment"])) ? "#" . $parse_url["fragment"] : "")
- ;
- }
-
- protected function getValidResponseTypes()
- {
- return array(
- self::RESPONSE_TYPE_ACCESS_TOKEN,
- self::RESPONSE_TYPE_AUTHORIZATION_CODE,
- );
- }
-
- /**
- * Internal method for validating redirect URI supplied
- *
- * @param string $inputUri The submitted URI to be validated
- * @param string $registeredUriString The allowed URI(s) to validate against. Can be a space-delimited string of URIs to
- * allow for multiple URIs
- *
- * @see http://tools.ietf.org/html/rfc6749#section-3.1.2
- */
- protected function validateRedirectUri($inputUri, $registeredUriString)
- {
- if (!$inputUri || !$registeredUriString) {
- return false; // if either one is missing, assume INVALID
- }
-
- $registered_uris = explode(' ', $registeredUriString);
- foreach ($registered_uris as $registered_uri) {
- if ($this->config['require_exact_redirect_uri']) {
- // the input uri is validated against the registered uri using exact match
- if (strcmp($inputUri, $registered_uri) === 0) {
- return true;
- }
- } else {
- $registered_uri_length = strlen($registered_uri);
- if ($registered_uri_length === 0) {
- return false;
- }
-
- // the input uri is validated against the registered uri using case-insensitive match of the initial string
- // i.e. additional query parameters may be applied
- if (strcasecmp(substr($inputUri, 0, $registered_uri_length), $registered_uri) === 0) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Convenience methods to access the parameters derived from the validated request
- */
-
- public function getScope()
- {
- return $this->scope;
- }
-
- public function getState()
- {
- return $this->state;
- }
-
- public function getClientId()
- {
- return $this->client_id;
- }
-
- public function getRedirectUri()
- {
- return $this->redirect_uri;
- }
-
- public function getResponseType()
- {
- return $this->response_type;
- }
-}
diff --git a/library/oauth2/src/OAuth2/Controller/AuthorizeControllerInterface.php b/library/oauth2/src/OAuth2/Controller/AuthorizeControllerInterface.php
deleted file mode 100644
index fa07ae8d2..000000000
--- a/library/oauth2/src/OAuth2/Controller/AuthorizeControllerInterface.php
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-
-namespace OAuth2\Controller;
-
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-
-/**
- * This controller is called when a user should be authorized
- * by an authorization server. As OAuth2 does not handle
- * authorization directly, this controller ensures the request is valid, but
- * requires the application to determine the value of $is_authorized
- *
- * ex:
- * > $user_id = $this->somehowDetermineUserId();
- * > $is_authorized = $this->somehowDetermineUserAuthorization();
- * > $response = new OAuth2\Response();
- * > $authorizeController->handleAuthorizeRequest(
- * > OAuth2\Request::createFromGlobals(),
- * > $response,
- * > $is_authorized,
- * > $user_id);
- * > $response->send();
- *
- */
-interface AuthorizeControllerInterface
-{
- /**
- * List of possible authentication response types.
- * The "authorization_code" mechanism exclusively supports 'code'
- * and the "implicit" mechanism exclusively supports 'token'.
- *
- * @var string
- * @see http://tools.ietf.org/html/rfc6749#section-4.1.1
- * @see http://tools.ietf.org/html/rfc6749#section-4.2.1
- */
- const RESPONSE_TYPE_AUTHORIZATION_CODE = 'code';
- const RESPONSE_TYPE_ACCESS_TOKEN = 'token';
-
- public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null);
-
- public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response);
-}
diff --git a/library/oauth2/src/OAuth2/Controller/ResourceController.php b/library/oauth2/src/OAuth2/Controller/ResourceController.php
deleted file mode 100644
index e8588188f..000000000
--- a/library/oauth2/src/OAuth2/Controller/ResourceController.php
+++ /dev/null
@@ -1,111 +0,0 @@
-<?php
-
-namespace OAuth2\Controller;
-
-use OAuth2\TokenType\TokenTypeInterface;
-use OAuth2\Storage\AccessTokenInterface;
-use OAuth2\ScopeInterface;
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-use OAuth2\Scope;
-
-/**
- * @see OAuth2\Controller\ResourceControllerInterface
- */
-class ResourceController implements ResourceControllerInterface
-{
- private $token;
-
- protected $tokenType;
- protected $tokenStorage;
- protected $config;
- protected $scopeUtil;
-
- public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, $config = array(), ScopeInterface $scopeUtil = null)
- {
- $this->tokenType = $tokenType;
- $this->tokenStorage = $tokenStorage;
-
- $this->config = array_merge(array(
- 'www_realm' => 'Service',
- ), $config);
-
- if (is_null($scopeUtil)) {
- $scopeUtil = new Scope();
- }
- $this->scopeUtil = $scopeUtil;
- }
-
- public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null)
- {
- $token = $this->getAccessTokenData($request, $response);
-
- // Check if we have token data
- if (is_null($token)) {
- return false;
- }
-
- /**
- * Check scope, if provided
- * If token doesn't have a scope, it's null/empty, or it's insufficient, then throw 403
- * @see http://tools.ietf.org/html/rfc6750#section-3.1
- */
- if ($scope && (!isset($token["scope"]) || !$token["scope"] || !$this->scopeUtil->checkScope($scope, $token["scope"]))) {
- $response->setError(403, 'insufficient_scope', 'The request requires higher privileges than provided by the access token');
- $response->addHttpHeaders(array(
- 'WWW-Authenticate' => sprintf('%s realm="%s", scope="%s", error="%s", error_description="%s"',
- $this->tokenType->getTokenType(),
- $this->config['www_realm'],
- $scope,
- $response->getParameter('error'),
- $response->getParameter('error_description')
- )
- ));
-
- return false;
- }
-
- // allow retrieval of the token
- $this->token = $token;
-
- return (bool) $token;
- }
-
- public function getAccessTokenData(RequestInterface $request, ResponseInterface $response)
- {
- // Get the token parameter
- if ($token_param = $this->tokenType->getAccessTokenParameter($request, $response)) {
- // Get the stored token data (from the implementing subclass)
- // Check we have a well formed token
- // Check token expiration (expires is a mandatory paramter)
- if (!$token = $this->tokenStorage->getAccessToken($token_param)) {
- $response->setError(401, 'invalid_token', 'The access token provided is invalid');
- } elseif (!isset($token["expires"]) || !isset($token["client_id"])) {
- $response->setError(401, 'malformed_token', 'Malformed token (missing "expires")');
- } elseif (time() > $token["expires"]) {
- $response->setError(401, 'expired_token', 'The access token provided has expired');
- } else {
- return $token;
- }
- }
-
- $authHeader = sprintf('%s realm="%s"', $this->tokenType->getTokenType(), $this->config['www_realm']);
-
- if ($error = $response->getParameter('error')) {
- $authHeader = sprintf('%s, error="%s"', $authHeader, $error);
- if ($error_description = $response->getParameter('error_description')) {
- $authHeader = sprintf('%s, error_description="%s"', $authHeader, $error_description);
- }
- }
-
- $response->addHttpHeaders(array('WWW-Authenticate' => $authHeader));
-
- return null;
- }
-
- // convenience method to allow retrieval of the token
- public function getToken()
- {
- return $this->token;
- }
-}
diff --git a/library/oauth2/src/OAuth2/Controller/ResourceControllerInterface.php b/library/oauth2/src/OAuth2/Controller/ResourceControllerInterface.php
deleted file mode 100644
index 611421935..000000000
--- a/library/oauth2/src/OAuth2/Controller/ResourceControllerInterface.php
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-
-namespace OAuth2\Controller;
-
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-
-/**
- * This controller is called when a "resource" is requested.
- * call verifyResourceRequest in order to determine if the request
- * contains a valid token.
- *
- * ex:
- * > if (!$resourceController->verifyResourceRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response())) {
- * > $response->send(); // authorization failed
- * > die();
- * > }
- * > return json_encode($resource); // valid token! Send the stuff!
- *
- */
-interface ResourceControllerInterface
-{
- public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null);
-
- public function getAccessTokenData(RequestInterface $request, ResponseInterface $response);
-}
diff --git a/library/oauth2/src/OAuth2/Controller/TokenController.php b/library/oauth2/src/OAuth2/Controller/TokenController.php
deleted file mode 100644
index 42dab892f..000000000
--- a/library/oauth2/src/OAuth2/Controller/TokenController.php
+++ /dev/null
@@ -1,278 +0,0 @@
-<?php
-
-namespace OAuth2\Controller;
-
-use OAuth2\ResponseType\AccessTokenInterface;
-use OAuth2\ClientAssertionType\ClientAssertionTypeInterface;
-use OAuth2\GrantType\GrantTypeInterface;
-use OAuth2\ScopeInterface;
-use OAuth2\Scope;
-use OAuth2\Storage\ClientInterface;
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-
-/**
- * @see OAuth2\Controller\TokenControllerInterface
- */
-class TokenController implements TokenControllerInterface
-{
- protected $accessToken;
- protected $grantTypes;
- protected $clientAssertionType;
- protected $scopeUtil;
- protected $clientStorage;
-
- public function __construct(AccessTokenInterface $accessToken, ClientInterface $clientStorage, array $grantTypes = array(), ClientAssertionTypeInterface $clientAssertionType = null, ScopeInterface $scopeUtil = null)
- {
- if (is_null($clientAssertionType)) {
- foreach ($grantTypes as $grantType) {
- if (!$grantType instanceof ClientAssertionTypeInterface) {
- throw new \InvalidArgumentException('You must supply an instance of OAuth2\ClientAssertionType\ClientAssertionTypeInterface or only use grant types which implement OAuth2\ClientAssertionType\ClientAssertionTypeInterface');
- }
- }
- }
- $this->clientAssertionType = $clientAssertionType;
- $this->accessToken = $accessToken;
- $this->clientStorage = $clientStorage;
- foreach ($grantTypes as $grantType) {
- $this->addGrantType($grantType);
- }
-
- if (is_null($scopeUtil)) {
- $scopeUtil = new Scope();
- }
- $this->scopeUtil = $scopeUtil;
- }
-
- public function handleTokenRequest(RequestInterface $request, ResponseInterface $response)
- {
- if ($token = $this->grantAccessToken($request, $response)) {
- // @see http://tools.ietf.org/html/rfc6749#section-5.1
- // server MUST disable caching in headers when tokens are involved
- $response->setStatusCode(200);
- $response->addParameters($token);
- $response->addHttpHeaders(array(
- 'Cache-Control' => 'no-store',
- 'Pragma' => 'no-cache',
- 'Content-Type' => 'application/json'
- ));
- }
- }
-
- /**
- * Grant or deny a requested access token.
- * This would be called from the "/token" endpoint as defined in the spec.
- * You can call your endpoint whatever you want.
- *
- * @param $request - RequestInterface
- * Request object to grant access token
- *
- * @throws InvalidArgumentException
- * @throws LogicException
- *
- * @see http://tools.ietf.org/html/rfc6749#section-4
- * @see http://tools.ietf.org/html/rfc6749#section-10.6
- * @see http://tools.ietf.org/html/rfc6749#section-4.1.3
- *
- * @ingroup oauth2_section_4
- */
- public function grantAccessToken(RequestInterface $request, ResponseInterface $response)
- {
- if (strtolower($request->server('REQUEST_METHOD')) != 'post') {
- $response->setError(405, 'invalid_request', 'The request method must be POST when requesting an access token', '#section-3.2');
- $response->addHttpHeaders(array('Allow' => 'POST'));
-
- return null;
- }
-
- /**
- * Determine grant type from request
- * and validate the request for that grant type
- */
- if (!$grantTypeIdentifier = $request->request('grant_type')) {
- $response->setError(400, 'invalid_request', 'The grant type was not specified in the request');
-
- return null;
- }
-
- if (!isset($this->grantTypes[$grantTypeIdentifier])) {
- /* TODO: If this is an OAuth2 supported grant type that we have chosen not to implement, throw a 501 Not Implemented instead */
- $response->setError(400, 'unsupported_grant_type', sprintf('Grant type "%s" not supported', $grantTypeIdentifier));
-
- return null;
- }
-
- $grantType = $this->grantTypes[$grantTypeIdentifier];
-
- /**
- * Retrieve the client information from the request
- * ClientAssertionTypes allow for grant types which also assert the client data
- * in which case ClientAssertion is handled in the validateRequest method
- *
- * @see OAuth2\GrantType\JWTBearer
- * @see OAuth2\GrantType\ClientCredentials
- */
- if (!$grantType instanceof ClientAssertionTypeInterface) {
- if (!$this->clientAssertionType->validateRequest($request, $response)) {
- return null;
- }
- $clientId = $this->clientAssertionType->getClientId();
- }
-
- /**
- * Retrieve the grant type information from the request
- * The GrantTypeInterface object handles all validation
- * If the object is an instance of ClientAssertionTypeInterface,
- * That logic is handled here as well
- */
- if (!$grantType->validateRequest($request, $response)) {
- return null;
- }
-
- if ($grantType instanceof ClientAssertionTypeInterface) {
- $clientId = $grantType->getClientId();
- } else {
- // validate the Client ID (if applicable)
- if (!is_null($storedClientId = $grantType->getClientId()) && $storedClientId != $clientId) {
- $response->setError(400, 'invalid_grant', sprintf('%s doesn\'t exist or is invalid for the client', $grantTypeIdentifier));
-
- return null;
- }
- }
-
- /**
- * Validate the client can use the requested grant type
- */
- if (!$this->clientStorage->checkRestrictedGrantType($clientId, $grantTypeIdentifier)) {
- $response->setError(400, 'unauthorized_client', 'The grant type is unauthorized for this client_id');
-
- return false;
- }
-
- /**
- * Validate the scope of the token
- *
- * requestedScope - the scope specified in the token request
- * availableScope - the scope associated with the grant type
- * ex: in the case of the "Authorization Code" grant type,
- * the scope is specified in the authorize request
- *
- * @see http://tools.ietf.org/html/rfc6749#section-3.3
- */
-
- $requestedScope = $this->scopeUtil->getScopeFromRequest($request);
- $availableScope = $grantType->getScope();
-
- if ($requestedScope) {
- // validate the requested scope
- if ($availableScope) {
- if (!$this->scopeUtil->checkScope($requestedScope, $availableScope)) {
- $response->setError(400, 'invalid_scope', 'The scope requested is invalid for this request');
-
- return null;
- }
- } else {
- // validate the client has access to this scope
- if ($clientScope = $this->clientStorage->getClientScope($clientId)) {
- if (!$this->scopeUtil->checkScope($requestedScope, $clientScope)) {
- $response->setError(400, 'invalid_scope', 'The scope requested is invalid for this client');
-
- return false;
- }
- } elseif (!$this->scopeUtil->scopeExists($requestedScope)) {
- $response->setError(400, 'invalid_scope', 'An unsupported scope was requested');
-
- return null;
- }
- }
- } elseif ($availableScope) {
- // use the scope associated with this grant type
- $requestedScope = $availableScope;
- } else {
- // use a globally-defined default scope
- $defaultScope = $this->scopeUtil->getDefaultScope($clientId);
-
- // "false" means default scopes are not allowed
- if (false === $defaultScope) {
- $response->setError(400, 'invalid_scope', 'This application requires you specify a scope parameter');
-
- return null;
- }
-
- $requestedScope = $defaultScope;
- }
-
- return $grantType->createAccessToken($this->accessToken, $clientId, $grantType->getUserId(), $requestedScope);
- }
-
- /**
- * addGrantType
- *
- * @param grantType - OAuth2\GrantTypeInterface
- * the grant type to add for the specified identifier
- * @param identifier - string
- * a string passed in as "grant_type" in the response that will call this grantType
- */
- public function addGrantType(GrantTypeInterface $grantType, $identifier = null)
- {
- if (is_null($identifier) || is_numeric($identifier)) {
- $identifier = $grantType->getQuerystringIdentifier();
- }
-
- $this->grantTypes[$identifier] = $grantType;
- }
-
- public function handleRevokeRequest(RequestInterface $request, ResponseInterface $response)
- {
- if ($this->revokeToken($request, $response)) {
- $response->setStatusCode(200);
- $response->addParameters(array('revoked' => true));
- }
- }
-
- /**
- * Revoke a refresh or access token. Returns true on success and when tokens are invalid
- *
- * Note: invalid tokens do not cause an error response since the client
- * cannot handle such an error in a reasonable way. Moreover, the
- * purpose of the revocation request, invalidating the particular token,
- * is already achieved.
- *
- * @param RequestInterface $request
- * @param ResponseInterface $response
- * @return bool|null
- */
- public function revokeToken(RequestInterface $request, ResponseInterface $response)
- {
- if (strtolower($request->server('REQUEST_METHOD')) != 'post') {
- $response->setError(405, 'invalid_request', 'The request method must be POST when revoking an access token', '#section-3.2');
- $response->addHttpHeaders(array('Allow' => 'POST'));
-
- return null;
- }
-
- $token_type_hint = $request->request('token_type_hint');
- if (!in_array($token_type_hint, array(null, 'access_token', 'refresh_token'), true)) {
- $response->setError(400, 'invalid_request', 'Token type hint must be either \'access_token\' or \'refresh_token\'');
-
- return null;
- }
-
- $token = $request->request('token');
- if ($token === null) {
- $response->setError(400, 'invalid_request', 'Missing token parameter to revoke');
-
- return null;
- }
-
- // @todo remove this check for v2.0
- if (!method_exists($this->accessToken, 'revokeToken')) {
- $class = get_class($this->accessToken);
- throw new \RuntimeException("AccessToken {$class} does not implement required revokeToken method");
- }
-
- $this->accessToken->revokeToken($token, $token_type_hint);
-
- return true;
- }
-}
diff --git a/library/oauth2/src/OAuth2/Controller/TokenControllerInterface.php b/library/oauth2/src/OAuth2/Controller/TokenControllerInterface.php
deleted file mode 100644
index 72d72570f..000000000
--- a/library/oauth2/src/OAuth2/Controller/TokenControllerInterface.php
+++ /dev/null
@@ -1,32 +0,0 @@
-<?php
-
-namespace OAuth2\Controller;
-
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-
-/**
- * This controller is called when a token is being requested.
- * it is called to handle all grant types the application supports.
- * It also validates the client's credentials
- *
- * ex:
- * > $tokenController->handleTokenRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response());
- * > $response->send();
- *
- */
-interface TokenControllerInterface
-{
- /**
- * handleTokenRequest
- *
- * @param $request
- * OAuth2\RequestInterface - The current http request
- * @param $response
- * OAuth2\ResponseInterface - An instance of OAuth2\ResponseInterface to contain the response data
- *
- */
- public function handleTokenRequest(RequestInterface $request, ResponseInterface $response);
-
- public function grantAccessToken(RequestInterface $request, ResponseInterface $response);
-}
diff --git a/library/oauth2/src/OAuth2/Encryption/EncryptionInterface.php b/library/oauth2/src/OAuth2/Encryption/EncryptionInterface.php
deleted file mode 100644
index 2d336c664..000000000
--- a/library/oauth2/src/OAuth2/Encryption/EncryptionInterface.php
+++ /dev/null
@@ -1,11 +0,0 @@
-<?php
-
-namespace OAuth2\Encryption;
-
-interface EncryptionInterface
-{
- public function encode($payload, $key, $algorithm = null);
- public function decode($payload, $key, $algorithm = null);
- public function urlSafeB64Encode($data);
- public function urlSafeB64Decode($b64);
-}
diff --git a/library/oauth2/src/OAuth2/Encryption/FirebaseJwt.php b/library/oauth2/src/OAuth2/Encryption/FirebaseJwt.php
deleted file mode 100644
index 1b527e0a0..000000000
--- a/library/oauth2/src/OAuth2/Encryption/FirebaseJwt.php
+++ /dev/null
@@ -1,47 +0,0 @@
-<?php
-
-namespace OAuth2\Encryption;
-
-/**
- * Bridge file to use the firebase/php-jwt package for JWT encoding and decoding.
- * @author Francis Chuang <francis.chuang@gmail.com>
- */
-class FirebaseJwt implements EncryptionInterface
-{
- public function __construct()
- {
- if (!class_exists('\JWT')) {
- throw new \ErrorException('firebase/php-jwt must be installed to use this feature. You can do this by running "composer require firebase/php-jwt"');
- }
- }
-
- public function encode($payload, $key, $alg = 'HS256', $keyId = null)
- {
- return \JWT::encode($payload, $key, $alg, $keyId);
- }
-
- public function decode($jwt, $key = null, $allowedAlgorithms = null)
- {
- try {
-
- //Maintain BC: Do not verify if no algorithms are passed in.
- if (!$allowedAlgorithms) {
- $key = null;
- }
-
- return (array)\JWT::decode($jwt, $key, $allowedAlgorithms);
- } catch (\Exception $e) {
- return false;
- }
- }
-
- public function urlSafeB64Encode($data)
- {
- return \JWT::urlsafeB64Encode($data);
- }
-
- public function urlSafeB64Decode($b64)
- {
- return \JWT::urlsafeB64Decode($b64);
- }
-}
diff --git a/library/oauth2/src/OAuth2/Encryption/Jwt.php b/library/oauth2/src/OAuth2/Encryption/Jwt.php
deleted file mode 100644
index ee576e643..000000000
--- a/library/oauth2/src/OAuth2/Encryption/Jwt.php
+++ /dev/null
@@ -1,173 +0,0 @@
-<?php
-
-namespace OAuth2\Encryption;
-
-/**
- * @link https://github.com/F21/jwt
- * @author F21
- */
-class Jwt implements EncryptionInterface
-{
- public function encode($payload, $key, $algo = 'HS256')
- {
- $header = $this->generateJwtHeader($payload, $algo);
-
- $segments = array(
- $this->urlSafeB64Encode(json_encode($header)),
- $this->urlSafeB64Encode(json_encode($payload))
- );
-
- $signing_input = implode('.', $segments);
-
- $signature = $this->sign($signing_input, $key, $algo);
- $segments[] = $this->urlsafeB64Encode($signature);
-
- return implode('.', $segments);
- }
-
- public function decode($jwt, $key = null, $allowedAlgorithms = true)
- {
- if (!strpos($jwt, '.')) {
- return false;
- }
-
- $tks = explode('.', $jwt);
-
- if (count($tks) != 3) {
- return false;
- }
-
- list($headb64, $payloadb64, $cryptob64) = $tks;
-
- if (null === ($header = json_decode($this->urlSafeB64Decode($headb64), true))) {
- return false;
- }
-
- if (null === $payload = json_decode($this->urlSafeB64Decode($payloadb64), true)) {
- return false;
- }
-
- $sig = $this->urlSafeB64Decode($cryptob64);
-
- if ((bool) $allowedAlgorithms) {
- if (!isset($header['alg'])) {
- return false;
- }
-
- // check if bool arg supplied here to maintain BC
- if (is_array($allowedAlgorithms) && !in_array($header['alg'], $allowedAlgorithms)) {
- return false;
- }
-
- if (!$this->verifySignature($sig, "$headb64.$payloadb64", $key, $header['alg'])) {
- return false;
- }
- }
-
- return $payload;
- }
-
- private function verifySignature($signature, $input, $key, $algo = 'HS256')
- {
- // use constants when possible, for HipHop support
- switch ($algo) {
- case'HS256':
- case'HS384':
- case'HS512':
- return $this->hash_equals(
- $this->sign($input, $key, $algo),
- $signature
- );
-
- case 'RS256':
- return openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA256') ? OPENSSL_ALGO_SHA256 : 'sha256') === 1;
-
- case 'RS384':
- return @openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA384') ? OPENSSL_ALGO_SHA384 : 'sha384') === 1;
-
- case 'RS512':
- return @openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512') === 1;
-
- default:
- throw new \InvalidArgumentException("Unsupported or invalid signing algorithm.");
- }
- }
-
- private function sign($input, $key, $algo = 'HS256')
- {
- switch ($algo) {
- case 'HS256':
- return hash_hmac('sha256', $input, $key, true);
-
- case 'HS384':
- return hash_hmac('sha384', $input, $key, true);
-
- case 'HS512':
- return hash_hmac('sha512', $input, $key, true);
-
- case 'RS256':
- return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA256') ? OPENSSL_ALGO_SHA256 : 'sha256');
-
- case 'RS384':
- return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA384') ? OPENSSL_ALGO_SHA384 : 'sha384');
-
- case 'RS512':
- return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512');
-
- default:
- throw new \Exception("Unsupported or invalid signing algorithm.");
- }
- }
-
- private function generateRSASignature($input, $key, $algo)
- {
- if (!openssl_sign($input, $signature, $key, $algo)) {
- throw new \Exception("Unable to sign data.");
- }
-
- return $signature;
- }
-
- public function urlSafeB64Encode($data)
- {
- $b64 = base64_encode($data);
- $b64 = str_replace(array('+', '/', "\r", "\n", '='),
- array('-', '_'),
- $b64);
-
- return $b64;
- }
-
- public function urlSafeB64Decode($b64)
- {
- $b64 = str_replace(array('-', '_'),
- array('+', '/'),
- $b64);
-
- return base64_decode($b64);
- }
-
- /**
- * Override to create a custom header
- */
- protected function generateJwtHeader($payload, $algorithm)
- {
- return array(
- 'typ' => 'JWT',
- 'alg' => $algorithm,
- );
- }
-
- protected function hash_equals($a, $b)
- {
- if (function_exists('hash_equals')) {
- return hash_equals($a, $b);
- }
- $diff = strlen($a) ^ strlen($b);
- for ($i = 0; $i < strlen($a) && $i < strlen($b); $i++) {
- $diff |= ord($a[$i]) ^ ord($b[$i]);
- }
-
- return $diff === 0;
- }
-}
diff --git a/library/oauth2/src/OAuth2/GrantType/AuthorizationCode.php b/library/oauth2/src/OAuth2/GrantType/AuthorizationCode.php
deleted file mode 100644
index e8995204c..000000000
--- a/library/oauth2/src/OAuth2/GrantType/AuthorizationCode.php
+++ /dev/null
@@ -1,100 +0,0 @@
-<?php
-
-namespace OAuth2\GrantType;
-
-use OAuth2\Storage\AuthorizationCodeInterface;
-use OAuth2\ResponseType\AccessTokenInterface;
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-
-/**
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-class AuthorizationCode implements GrantTypeInterface
-{
- protected $storage;
- protected $authCode;
-
- /**
- * @param OAuth2\Storage\AuthorizationCodeInterface $storage REQUIRED Storage class for retrieving authorization code information
- */
- public function __construct(AuthorizationCodeInterface $storage)
- {
- $this->storage = $storage;
- }
-
- public function getQuerystringIdentifier()
- {
- return 'authorization_code';
- }
-
- public function validateRequest(RequestInterface $request, ResponseInterface $response)
- {
- if (!$request->request('code')) {
- $response->setError(400, 'invalid_request', 'Missing parameter: "code" is required');
-
- return false;
- }
-
- $code = $request->request('code');
- if (!$authCode = $this->storage->getAuthorizationCode($code)) {
- $response->setError(400, 'invalid_grant', 'Authorization code doesn\'t exist or is invalid for the client');
-
- return false;
- }
-
- /*
- * 4.1.3 - ensure that the "redirect_uri" parameter is present if the "redirect_uri" parameter was included in the initial authorization request
- * @uri - http://tools.ietf.org/html/rfc6749#section-4.1.3
- */
- if (isset($authCode['redirect_uri']) && $authCode['redirect_uri']) {
- if (!$request->request('redirect_uri') || urldecode($request->request('redirect_uri')) != $authCode['redirect_uri']) {
- $response->setError(400, 'redirect_uri_mismatch', "The redirect URI is missing or do not match", "#section-4.1.3");
-
- return false;
- }
- }
-
- if (!isset($authCode['expires'])) {
- throw new \Exception('Storage must return authcode with a value for "expires"');
- }
-
- if ($authCode["expires"] < time()) {
- $response->setError(400, 'invalid_grant', "The authorization code has expired");
-
- return false;
- }
-
- if (!isset($authCode['code'])) {
- $authCode['code'] = $code; // used to expire the code after the access token is granted
- }
-
- $this->authCode = $authCode;
-
- return true;
- }
-
- public function getClientId()
- {
- return $this->authCode['client_id'];
- }
-
- public function getScope()
- {
- return isset($this->authCode['scope']) ? $this->authCode['scope'] : null;
- }
-
- public function getUserId()
- {
- return isset($this->authCode['user_id']) ? $this->authCode['user_id'] : null;
- }
-
- public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
- {
- $token = $accessToken->createAccessToken($client_id, $user_id, $scope);
- $this->storage->expireAuthorizationCode($this->authCode['code']);
-
- return $token;
- }
-}
diff --git a/library/oauth2/src/OAuth2/GrantType/ClientCredentials.php b/library/oauth2/src/OAuth2/GrantType/ClientCredentials.php
deleted file mode 100644
index f953e4e8d..000000000
--- a/library/oauth2/src/OAuth2/GrantType/ClientCredentials.php
+++ /dev/null
@@ -1,67 +0,0 @@
-<?php
-
-namespace OAuth2\GrantType;
-
-use OAuth2\ClientAssertionType\HttpBasic;
-use OAuth2\ResponseType\AccessTokenInterface;
-use OAuth2\Storage\ClientCredentialsInterface;
-
-/**
- * @author Brent Shaffer <bshafs at gmail dot com>
- *
- * @see OAuth2\ClientAssertionType_HttpBasic
- */
-class ClientCredentials extends HttpBasic implements GrantTypeInterface
-{
- private $clientData;
-
- public function __construct(ClientCredentialsInterface $storage, array $config = array())
- {
- /**
- * The client credentials grant type MUST only be used by confidential clients
- *
- * @see http://tools.ietf.org/html/rfc6749#section-4.4
- */
- $config['allow_public_clients'] = false;
-
- parent::__construct($storage, $config);
- }
-
- public function getQuerystringIdentifier()
- {
- return 'client_credentials';
- }
-
- public function getScope()
- {
- $this->loadClientData();
-
- return isset($this->clientData['scope']) ? $this->clientData['scope'] : null;
- }
-
- public function getUserId()
- {
- $this->loadClientData();
-
- return isset($this->clientData['user_id']) ? $this->clientData['user_id'] : null;
- }
-
- public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
- {
- /**
- * Client Credentials Grant does NOT include a refresh token
- *
- * @see http://tools.ietf.org/html/rfc6749#section-4.4.3
- */
- $includeRefreshToken = false;
-
- return $accessToken->createAccessToken($client_id, $user_id, $scope, $includeRefreshToken);
- }
-
- private function loadClientData()
- {
- if (!$this->clientData) {
- $this->clientData = $this->storage->getClientDetails($this->getClientId());
- }
- }
-}
diff --git a/library/oauth2/src/OAuth2/GrantType/GrantTypeInterface.php b/library/oauth2/src/OAuth2/GrantType/GrantTypeInterface.php
deleted file mode 100644
index 98489e9c1..000000000
--- a/library/oauth2/src/OAuth2/GrantType/GrantTypeInterface.php
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-
-namespace OAuth2\GrantType;
-
-use OAuth2\ResponseType\AccessTokenInterface;
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-
-/**
- * Interface for all OAuth2 Grant Types
- */
-interface GrantTypeInterface
-{
- public function getQuerystringIdentifier();
- public function validateRequest(RequestInterface $request, ResponseInterface $response);
- public function getClientId();
- public function getUserId();
- public function getScope();
- public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope);
-}
diff --git a/library/oauth2/src/OAuth2/GrantType/JwtBearer.php b/library/oauth2/src/OAuth2/GrantType/JwtBearer.php
deleted file mode 100644
index bb11a6954..000000000
--- a/library/oauth2/src/OAuth2/GrantType/JwtBearer.php
+++ /dev/null
@@ -1,226 +0,0 @@
-<?php
-
-namespace OAuth2\GrantType;
-
-use OAuth2\ClientAssertionType\ClientAssertionTypeInterface;
-use OAuth2\Storage\JwtBearerInterface;
-use OAuth2\Encryption\Jwt;
-use OAuth2\Encryption\EncryptionInterface;
-use OAuth2\ResponseType\AccessTokenInterface;
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-
-/**
- * The JWT bearer authorization grant implements JWT (JSON Web Tokens) as a grant type per the IETF draft.
- *
- * @see http://tools.ietf.org/html/draft-ietf-oauth-jwt-bearer-04#section-4
- *
- * @author F21
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
-{
- private $jwt;
-
- protected $storage;
- protected $audience;
- protected $jwtUtil;
- protected $allowedAlgorithms;
-
- /**
- * Creates an instance of the JWT bearer grant type.
- *
- * @param OAuth2\Storage\JWTBearerInterface|JwtBearerInterface $storage A valid storage interface that implements storage hooks for the JWT bearer grant type.
- * @param string $audience The audience to validate the token against. This is usually the full URI of the OAuth token requests endpoint.
- * @param EncryptionInterface|OAuth2\Encryption\JWT $jwtUtil OPTONAL The class used to decode, encode and verify JWTs.
- * @param array $config
- */
- public function __construct(JwtBearerInterface $storage, $audience, EncryptionInterface $jwtUtil = null, array $config = array())
- {
- $this->storage = $storage;
- $this->audience = $audience;
-
- if (is_null($jwtUtil)) {
- $jwtUtil = new Jwt();
- }
-
- $this->config = array_merge(array(
- 'allowed_algorithms' => array('RS256', 'RS384', 'RS512')
- ), $config);
-
- $this->jwtUtil = $jwtUtil;
-
- $this->allowedAlgorithms = $this->config['allowed_algorithms'];
- }
-
- /**
- * Returns the grant_type get parameter to identify the grant type request as JWT bearer authorization grant.
- *
- * @return
- * The string identifier for grant_type.
- *
- * @see OAuth2\GrantType\GrantTypeInterface::getQuerystringIdentifier()
- */
- public function getQuerystringIdentifier()
- {
- return 'urn:ietf:params:oauth:grant-type:jwt-bearer';
- }
-
- /**
- * Validates the data from the decoded JWT.
- *
- * @return
- * TRUE if the JWT request is valid and can be decoded. Otherwise, FALSE is returned.
- *
- * @see OAuth2\GrantType\GrantTypeInterface::getTokenData()
- */
- public function validateRequest(RequestInterface $request, ResponseInterface $response)
- {
- if (!$request->request("assertion")) {
- $response->setError(400, 'invalid_request', 'Missing parameters: "assertion" required');
-
- return null;
- }
-
- // Store the undecoded JWT for later use
- $undecodedJWT = $request->request('assertion');
-
- // Decode the JWT
- $jwt = $this->jwtUtil->decode($request->request('assertion'), null, false);
-
- if (!$jwt) {
- $response->setError(400, 'invalid_request', "JWT is malformed");
-
- return null;
- }
-
- // ensure these properties contain a value
- // @todo: throw malformed error for missing properties
- $jwt = array_merge(array(
- 'scope' => null,
- 'iss' => null,
- 'sub' => null,
- 'aud' => null,
- 'exp' => null,
- 'nbf' => null,
- 'iat' => null,
- 'jti' => null,
- 'typ' => null,
- ), $jwt);
-
- if (!isset($jwt['iss'])) {
- $response->setError(400, 'invalid_grant', "Invalid issuer (iss) provided");
-
- return null;
- }
-
- if (!isset($jwt['sub'])) {
- $response->setError(400, 'invalid_grant', "Invalid subject (sub) provided");
-
- return null;
- }
-
- if (!isset($jwt['exp'])) {
- $response->setError(400, 'invalid_grant', "Expiration (exp) time must be present");
-
- return null;
- }
-
- // Check expiration
- if (ctype_digit($jwt['exp'])) {
- if ($jwt['exp'] <= time()) {
- $response->setError(400, 'invalid_grant', "JWT has expired");
-
- return null;
- }
- } else {
- $response->setError(400, 'invalid_grant', "Expiration (exp) time must be a unix time stamp");
-
- return null;
- }
-
- // Check the not before time
- if ($notBefore = $jwt['nbf']) {
- if (ctype_digit($notBefore)) {
- if ($notBefore > time()) {
- $response->setError(400, 'invalid_grant', "JWT cannot be used before the Not Before (nbf) time");
-
- return null;
- }
- } else {
- $response->setError(400, 'invalid_grant', "Not Before (nbf) time must be a unix time stamp");
-
- return null;
- }
- }
-
- // Check the audience if required to match
- if (!isset($jwt['aud']) || ($jwt['aud'] != $this->audience)) {
- $response->setError(400, 'invalid_grant', "Invalid audience (aud)");
-
- return null;
- }
-
- // Check the jti (nonce)
- // @see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-13#section-4.1.7
- if (isset($jwt['jti'])) {
- $jti = $this->storage->getJti($jwt['iss'], $jwt['sub'], $jwt['aud'], $jwt['exp'], $jwt['jti']);
-
- //Reject if jti is used and jwt is still valid (exp parameter has not expired).
- if ($jti && $jti['expires'] > time()) {
- $response->setError(400, 'invalid_grant', "JSON Token Identifier (jti) has already been used");
-
- return null;
- } else {
- $this->storage->setJti($jwt['iss'], $jwt['sub'], $jwt['aud'], $jwt['exp'], $jwt['jti']);
- }
- }
-
- // Get the iss's public key
- // @see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06#section-4.1.1
- if (!$key = $this->storage->getClientKey($jwt['iss'], $jwt['sub'])) {
- $response->setError(400, 'invalid_grant', "Invalid issuer (iss) or subject (sub) provided");
-
- return null;
- }
-
- // Verify the JWT
- if (!$this->jwtUtil->decode($undecodedJWT, $key, $this->allowedAlgorithms)) {
- $response->setError(400, 'invalid_grant', "JWT failed signature verification");
-
- return null;
- }
-
- $this->jwt = $jwt;
-
- return true;
- }
-
- public function getClientId()
- {
- return $this->jwt['iss'];
- }
-
- public function getUserId()
- {
- return $this->jwt['sub'];
- }
-
- public function getScope()
- {
- return null;
- }
-
- /**
- * Creates an access token that is NOT associated with a refresh token.
- * If a subject (sub) the name of the user/account we are accessing data on behalf of.
- *
- * @see OAuth2\GrantType\GrantTypeInterface::createAccessToken()
- */
- public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
- {
- $includeRefreshToken = false;
-
- return $accessToken->createAccessToken($client_id, $user_id, $scope, $includeRefreshToken);
- }
-}
diff --git a/library/oauth2/src/OAuth2/GrantType/RefreshToken.php b/library/oauth2/src/OAuth2/GrantType/RefreshToken.php
deleted file mode 100644
index e55385222..000000000
--- a/library/oauth2/src/OAuth2/GrantType/RefreshToken.php
+++ /dev/null
@@ -1,111 +0,0 @@
-<?php
-
-namespace OAuth2\GrantType;
-
-use OAuth2\Storage\RefreshTokenInterface;
-use OAuth2\ResponseType\AccessTokenInterface;
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-
-/**
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-class RefreshToken implements GrantTypeInterface
-{
- private $refreshToken;
-
- protected $storage;
- protected $config;
-
- /**
- * @param OAuth2\Storage\RefreshTokenInterface $storage REQUIRED Storage class for retrieving refresh token information
- * @param array $config OPTIONAL Configuration options for the server
- * <code>
- * $config = array(
- * 'always_issue_new_refresh_token' => true, // whether to issue a new refresh token upon successful token request
- * 'unset_refresh_token_after_use' => true // whether to unset the refresh token after after using
- * );
- * </code>
- */
- public function __construct(RefreshTokenInterface $storage, $config = array())
- {
- $this->config = array_merge(array(
- 'always_issue_new_refresh_token' => false,
- 'unset_refresh_token_after_use' => true
- ), $config);
-
- // to preserve B.C. with v1.6
- // @see https://github.com/bshaffer/oauth2-server-php/pull/580
- // @todo - remove in v2.0
- if (isset($config['always_issue_new_refresh_token']) && !isset($config['unset_refresh_token_after_use'])) {
- $this->config['unset_refresh_token_after_use'] = $config['always_issue_new_refresh_token'];
- }
-
- $this->storage = $storage;
- }
-
- public function getQuerystringIdentifier()
- {
- return 'refresh_token';
- }
-
- public function validateRequest(RequestInterface $request, ResponseInterface $response)
- {
- if (!$request->request("refresh_token")) {
- $response->setError(400, 'invalid_request', 'Missing parameter: "refresh_token" is required');
-
- return null;
- }
-
- if (!$refreshToken = $this->storage->getRefreshToken($request->request("refresh_token"))) {
- $response->setError(400, 'invalid_grant', 'Invalid refresh token');
-
- return null;
- }
-
- if ($refreshToken['expires'] > 0 && $refreshToken["expires"] < time()) {
- $response->setError(400, 'invalid_grant', 'Refresh token has expired');
-
- return null;
- }
-
- // store the refresh token locally so we can delete it when a new refresh token is generated
- $this->refreshToken = $refreshToken;
-
- return true;
- }
-
- public function getClientId()
- {
- return $this->refreshToken['client_id'];
- }
-
- public function getUserId()
- {
- return isset($this->refreshToken['user_id']) ? $this->refreshToken['user_id'] : null;
- }
-
- public function getScope()
- {
- return isset($this->refreshToken['scope']) ? $this->refreshToken['scope'] : null;
- }
-
- public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
- {
- /*
- * It is optional to force a new refresh token when a refresh token is used.
- * However, if a new refresh token is issued, the old one MUST be expired
- * @see http://tools.ietf.org/html/rfc6749#section-6
- */
- $issueNewRefreshToken = $this->config['always_issue_new_refresh_token'];
- $unsetRefreshToken = $this->config['unset_refresh_token_after_use'];
- $token = $accessToken->createAccessToken($client_id, $user_id, $scope, $issueNewRefreshToken);
-
- if ($unsetRefreshToken) {
- $this->storage->unsetRefreshToken($this->refreshToken['refresh_token']);
- }
-
- return $token;
- }
-}
diff --git a/library/oauth2/src/OAuth2/GrantType/UserCredentials.php b/library/oauth2/src/OAuth2/GrantType/UserCredentials.php
deleted file mode 100644
index f165538ba..000000000
--- a/library/oauth2/src/OAuth2/GrantType/UserCredentials.php
+++ /dev/null
@@ -1,83 +0,0 @@
-<?php
-
-namespace OAuth2\GrantType;
-
-use OAuth2\Storage\UserCredentialsInterface;
-use OAuth2\ResponseType\AccessTokenInterface;
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-
-/**
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-class UserCredentials implements GrantTypeInterface
-{
- private $userInfo;
-
- protected $storage;
-
- /**
- * @param OAuth2\Storage\UserCredentialsInterface $storage REQUIRED Storage class for retrieving user credentials information
- */
- public function __construct(UserCredentialsInterface $storage)
- {
- $this->storage = $storage;
- }
-
- public function getQuerystringIdentifier()
- {
- return 'password';
- }
-
- public function validateRequest(RequestInterface $request, ResponseInterface $response)
- {
- if (!$request->request("password") || !$request->request("username")) {
- $response->setError(400, 'invalid_request', 'Missing parameters: "username" and "password" required');
-
- return null;
- }
-
- if (!$this->storage->checkUserCredentials($request->request("username"), $request->request("password"))) {
- $response->setError(401, 'invalid_grant', 'Invalid username and password combination');
-
- return null;
- }
-
- $userInfo = $this->storage->getUserDetails($request->request("username"));
-
- if (empty($userInfo)) {
- $response->setError(400, 'invalid_grant', 'Unable to retrieve user information');
-
- return null;
- }
-
- if (!isset($userInfo['user_id'])) {
- throw new \LogicException("you must set the user_id on the array returned by getUserDetails");
- }
-
- $this->userInfo = $userInfo;
-
- return true;
- }
-
- public function getClientId()
- {
- return null;
- }
-
- public function getUserId()
- {
- return $this->userInfo['user_id'];
- }
-
- public function getScope()
- {
- return isset($this->userInfo['scope']) ? $this->userInfo['scope'] : null;
- }
-
- public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
- {
- return $accessToken->createAccessToken($client_id, $user_id, $scope);
- }
-}
diff --git a/library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeController.php b/library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeController.php
deleted file mode 100644
index c9b5c6af7..000000000
--- a/library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeController.php
+++ /dev/null
@@ -1,106 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\Controller;
-
-use OAuth2\Controller\AuthorizeController as BaseAuthorizeController;
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-
-/**
- * @see OAuth2\Controller\AuthorizeControllerInterface
- */
-class AuthorizeController extends BaseAuthorizeController implements AuthorizeControllerInterface
-{
- private $nonce;
-
- protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null)
- {
- $prompt = $request->query('prompt', 'consent');
- if ($prompt == 'none') {
- if (is_null($user_id)) {
- $error = 'login_required';
- $error_message = 'The user must log in';
- } else {
- $error = 'interaction_required';
- $error_message = 'The user must grant access to your application';
- }
- } else {
- $error = 'consent_required';
- $error_message = 'The user denied access to your application';
- }
-
- $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->getState(), $error, $error_message);
- }
-
- protected function buildAuthorizeParameters($request, $response, $user_id)
- {
- if (!$params = parent::buildAuthorizeParameters($request, $response, $user_id)) {
- return;
- }
-
- // Generate an id token if needed.
- if ($this->needsIdToken($this->getScope()) && $this->getResponseType() == self::RESPONSE_TYPE_AUTHORIZATION_CODE) {
- $params['id_token'] = $this->responseTypes['id_token']->createIdToken($this->getClientId(), $user_id, $this->nonce);
- }
-
- // add the nonce to return with the redirect URI
- $params['nonce'] = $this->nonce;
-
- return $params;
- }
-
- public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response)
- {
- if (!parent::validateAuthorizeRequest($request, $response)) {
- return false;
- }
-
- $nonce = $request->query('nonce');
-
- // Validate required nonce for "id_token" and "id_token token"
- if (!$nonce && in_array($this->getResponseType(), array(self::RESPONSE_TYPE_ID_TOKEN, self::RESPONSE_TYPE_ID_TOKEN_TOKEN))) {
- $response->setError(400, 'invalid_nonce', 'This application requires you specify a nonce parameter');
-
- return false;
- }
-
- $this->nonce = $nonce;
-
- return true;
- }
-
- protected function getValidResponseTypes()
- {
- return array(
- self::RESPONSE_TYPE_ACCESS_TOKEN,
- self::RESPONSE_TYPE_AUTHORIZATION_CODE,
- self::RESPONSE_TYPE_ID_TOKEN,
- self::RESPONSE_TYPE_ID_TOKEN_TOKEN,
- self::RESPONSE_TYPE_CODE_ID_TOKEN,
- );
- }
-
- /**
- * Returns whether the current request needs to generate an id token.
- *
- * ID Tokens are a part of the OpenID Connect specification, so this
- * method checks whether OpenID Connect is enabled in the server settings
- * and whether the openid scope was requested.
- *
- * @param $request_scope
- * A space-separated string of scopes.
- *
- * @return
- * TRUE if an id token is needed, FALSE otherwise.
- */
- public function needsIdToken($request_scope)
- {
- // see if the "openid" scope exists in the requested scope
- return $this->scopeUtil->checkScope('openid', $request_scope);
- }
-
- public function getNonce()
- {
- return $this->nonce;
- }
-}
diff --git a/library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php b/library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php
deleted file mode 100644
index 1e231d844..000000000
--- a/library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\Controller;
-
-interface AuthorizeControllerInterface
-{
- const RESPONSE_TYPE_ID_TOKEN = 'id_token';
- const RESPONSE_TYPE_ID_TOKEN_TOKEN = 'id_token token';
- const RESPONSE_TYPE_CODE_ID_TOKEN = 'code id_token';
-}
diff --git a/library/oauth2/src/OAuth2/OpenID/Controller/UserInfoController.php b/library/oauth2/src/OAuth2/OpenID/Controller/UserInfoController.php
deleted file mode 100644
index 30cb942d0..000000000
--- a/library/oauth2/src/OAuth2/OpenID/Controller/UserInfoController.php
+++ /dev/null
@@ -1,58 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\Controller;
-
-use OAuth2\Scope;
-use OAuth2\TokenType\TokenTypeInterface;
-use OAuth2\Storage\AccessTokenInterface;
-use OAuth2\OpenID\Storage\UserClaimsInterface;
-use OAuth2\Controller\ResourceController;
-use OAuth2\ScopeInterface;
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-
-/**
- * @see OAuth2\Controller\UserInfoControllerInterface
- */
-class UserInfoController extends ResourceController implements UserInfoControllerInterface
-{
- private $token;
-
- protected $tokenType;
- protected $tokenStorage;
- protected $userClaimsStorage;
- protected $config;
- protected $scopeUtil;
-
- public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, UserClaimsInterface $userClaimsStorage, $config = array(), ScopeInterface $scopeUtil = null)
- {
- $this->tokenType = $tokenType;
- $this->tokenStorage = $tokenStorage;
- $this->userClaimsStorage = $userClaimsStorage;
-
- $this->config = array_merge(array(
- 'www_realm' => 'Service',
- ), $config);
-
- if (is_null($scopeUtil)) {
- $scopeUtil = new Scope();
- }
- $this->scopeUtil = $scopeUtil;
- }
-
- public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response)
- {
- if (!$this->verifyResourceRequest($request, $response, 'openid')) {
- return;
- }
-
- $token = $this->getToken();
- $claims = $this->userClaimsStorage->getUserClaims($token['user_id'], $token['scope']);
- // The sub Claim MUST always be returned in the UserInfo Response.
- // http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse
- $claims += array(
- 'sub' => $token['user_id'],
- );
- $response->addParameters($claims);
- }
-}
diff --git a/library/oauth2/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php b/library/oauth2/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php
deleted file mode 100644
index a89049d49..000000000
--- a/library/oauth2/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\Controller;
-
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-
-/**
- * This controller is called when the user claims for OpenID Connect's
- * UserInfo endpoint should be returned.
- *
- * ex:
- * > $response = new OAuth2\Response();
- * > $userInfoController->handleUserInfoRequest(
- * > OAuth2\Request::createFromGlobals(),
- * > $response;
- * > $response->send();
- *
- */
-interface UserInfoControllerInterface
-{
- public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response);
-}
diff --git a/library/oauth2/src/OAuth2/OpenID/GrantType/AuthorizationCode.php b/library/oauth2/src/OAuth2/OpenID/GrantType/AuthorizationCode.php
deleted file mode 100644
index 8ed1edc26..000000000
--- a/library/oauth2/src/OAuth2/OpenID/GrantType/AuthorizationCode.php
+++ /dev/null
@@ -1,33 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\GrantType;
-
-use OAuth2\GrantType\AuthorizationCode as BaseAuthorizationCode;
-use OAuth2\ResponseType\AccessTokenInterface;
-
-/**
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-class AuthorizationCode extends BaseAuthorizationCode
-{
- public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
- {
- $includeRefreshToken = true;
- if (isset($this->authCode['id_token'])) {
- // OpenID Connect requests include the refresh token only if the
- // offline_access scope has been requested and granted.
- $scopes = explode(' ', trim($scope));
- $includeRefreshToken = in_array('offline_access', $scopes);
- }
-
- $token = $accessToken->createAccessToken($client_id, $user_id, $scope, $includeRefreshToken);
- if (isset($this->authCode['id_token'])) {
- $token['id_token'] = $this->authCode['id_token'];
- }
-
- $this->storage->expireAuthorizationCode($this->authCode['code']);
-
- return $token;
- }
-}
diff --git a/library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php
deleted file mode 100644
index 8971954c5..000000000
--- a/library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\ResponseType;
-
-use OAuth2\ResponseType\AuthorizationCode as BaseAuthorizationCode;
-use OAuth2\OpenID\Storage\AuthorizationCodeInterface as AuthorizationCodeStorageInterface;
-
-/**
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-class AuthorizationCode extends BaseAuthorizationCode implements AuthorizationCodeInterface
-{
- public function __construct(AuthorizationCodeStorageInterface $storage, array $config = array())
- {
- parent::__construct($storage, $config);
- }
-
- public function getAuthorizeResponse($params, $user_id = null)
- {
- // build the URL to redirect to
- $result = array('query' => array());
-
- $params += array('scope' => null, 'state' => null, 'id_token' => null);
-
- $result['query']['code'] = $this->createAuthorizationCode($params['client_id'], $user_id, $params['redirect_uri'], $params['scope'], $params['id_token']);
-
- if (isset($params['state'])) {
- $result['query']['state'] = $params['state'];
- }
-
- return array($params['redirect_uri'], $result);
- }
-
- /**
- * Handle the creation of the authorization code.
- *
- * @param $client_id
- * Client identifier related to the authorization code
- * @param $user_id
- * User ID associated with the authorization code
- * @param $redirect_uri
- * An absolute URI to which the authorization server will redirect the
- * user-agent to when the end-user authorization step is completed.
- * @param $scope
- * (optional) Scopes to be stored in space-separated string.
- * @param $id_token
- * (optional) The OpenID Connect id_token.
- *
- * @see http://tools.ietf.org/html/rfc6749#section-4
- * @ingroup oauth2_section_4
- */
- public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null, $id_token = null)
- {
- $code = $this->generateAuthorizationCode();
- $this->storage->setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, time() + $this->config['auth_code_lifetime'], $scope, $id_token);
-
- return $code;
- }
-}
diff --git a/library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php
deleted file mode 100644
index ea4779255..000000000
--- a/library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\ResponseType;
-
-use OAuth2\ResponseType\AuthorizationCodeInterface as BaseAuthorizationCodeInterface;
-
-/**
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface
-{
- /**
- * Handle the creation of the authorization code.
- *
- * @param $client_id Client identifier related to the authorization code
- * @param $user_id User ID associated with the authorization code
- * @param $redirect_uri An absolute URI to which the authorization server will redirect the
- * user-agent to when the end-user authorization step is completed.
- * @param $scope OPTIONAL Scopes to be stored in space-separated string.
- * @param $id_token OPTIONAL The OpenID Connect id_token.
- *
- * @see http://tools.ietf.org/html/rfc6749#section-4
- * @ingroup oauth2_section_4
- */
- public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null, $id_token = null);
-}
diff --git a/library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdToken.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdToken.php
deleted file mode 100644
index ac7764d6c..000000000
--- a/library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdToken.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\ResponseType;
-
-class CodeIdToken implements CodeIdTokenInterface
-{
- protected $authCode;
- protected $idToken;
-
- public function __construct(AuthorizationCodeInterface $authCode, IdTokenInterface $idToken)
- {
- $this->authCode = $authCode;
- $this->idToken = $idToken;
- }
-
- public function getAuthorizeResponse($params, $user_id = null)
- {
- $result = $this->authCode->getAuthorizeResponse($params, $user_id);
- $resultIdToken = $this->idToken->getAuthorizeResponse($params, $user_id);
- $result[1]['query']['id_token'] = $resultIdToken[1]['fragment']['id_token'];
-
- return $result;
- }
-}
diff --git a/library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php
deleted file mode 100644
index 629adcca8..000000000
--- a/library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php
+++ /dev/null
@@ -1,9 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\ResponseType;
-
-use OAuth2\ResponseType\ResponseTypeInterface;
-
-interface CodeIdTokenInterface extends ResponseTypeInterface
-{
-}
diff --git a/library/oauth2/src/OAuth2/OpenID/ResponseType/IdToken.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/IdToken.php
deleted file mode 100644
index 97777fbf2..000000000
--- a/library/oauth2/src/OAuth2/OpenID/ResponseType/IdToken.php
+++ /dev/null
@@ -1,124 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\ResponseType;
-
-use OAuth2\Encryption\EncryptionInterface;
-use OAuth2\Encryption\Jwt;
-use OAuth2\Storage\PublicKeyInterface;
-use OAuth2\OpenID\Storage\UserClaimsInterface;
-
-class IdToken implements IdTokenInterface
-{
- protected $userClaimsStorage;
- protected $publicKeyStorage;
- protected $config;
- protected $encryptionUtil;
-
- public function __construct(UserClaimsInterface $userClaimsStorage, PublicKeyInterface $publicKeyStorage, array $config = array(), EncryptionInterface $encryptionUtil = null)
- {
- $this->userClaimsStorage = $userClaimsStorage;
- $this->publicKeyStorage = $publicKeyStorage;
- if (is_null($encryptionUtil)) {
- $encryptionUtil = new Jwt();
- }
- $this->encryptionUtil = $encryptionUtil;
-
- if (!isset($config['issuer'])) {
- throw new \LogicException('config parameter "issuer" must be set');
- }
- $this->config = array_merge(array(
- 'id_lifetime' => 3600,
- ), $config);
- }
-
- public function getAuthorizeResponse($params, $userInfo = null)
- {
- // build the URL to redirect to
- $result = array('query' => array());
- $params += array('scope' => null, 'state' => null, 'nonce' => null);
-
- // create the id token.
- list($user_id, $auth_time) = $this->getUserIdAndAuthTime($userInfo);
- $userClaims = $this->userClaimsStorage->getUserClaims($user_id, $params['scope']);
-
- $id_token = $this->createIdToken($params['client_id'], $userInfo, $params['nonce'], $userClaims, null);
- $result["fragment"] = array('id_token' => $id_token);
- if (isset($params['state'])) {
- $result["fragment"]["state"] = $params['state'];
- }
-
- return array($params['redirect_uri'], $result);
- }
-
- public function createIdToken($client_id, $userInfo, $nonce = null, $userClaims = null, $access_token = null)
- {
- // pull auth_time from user info if supplied
- list($user_id, $auth_time) = $this->getUserIdAndAuthTime($userInfo);
-
- $token = array(
- 'iss' => $this->config['issuer'],
- 'sub' => $user_id,
- 'aud' => $client_id,
- 'iat' => time(),
- 'exp' => time() + $this->config['id_lifetime'],
- 'auth_time' => $auth_time,
- );
-
- if ($nonce) {
- $token['nonce'] = $nonce;
- }
-
- if ($userClaims) {
- $token += $userClaims;
- }
-
- if ($access_token) {
- $token['at_hash'] = $this->createAtHash($access_token, $client_id);
- }
-
- return $this->encodeToken($token, $client_id);
- }
-
- protected function createAtHash($access_token, $client_id = null)
- {
- // maps HS256 and RS256 to sha256, etc.
- $algorithm = $this->publicKeyStorage->getEncryptionAlgorithm($client_id);
- $hash_algorithm = 'sha' . substr($algorithm, 2);
- $hash = hash($hash_algorithm, $access_token, true);
- $at_hash = substr($hash, 0, strlen($hash) / 2);
-
- return $this->encryptionUtil->urlSafeB64Encode($at_hash);
- }
-
- protected function encodeToken(array $token, $client_id = null)
- {
- $private_key = $this->publicKeyStorage->getPrivateKey($client_id);
- $algorithm = $this->publicKeyStorage->getEncryptionAlgorithm($client_id);
-
- return $this->encryptionUtil->encode($token, $private_key, $algorithm);
- }
-
- private function getUserIdAndAuthTime($userInfo)
- {
- $auth_time = null;
-
- // support an array for user_id / auth_time
- if (is_array($userInfo)) {
- if (!isset($userInfo['user_id'])) {
- throw new \LogicException('if $user_id argument is an array, user_id index must be set');
- }
-
- $auth_time = isset($userInfo['auth_time']) ? $userInfo['auth_time'] : null;
- $user_id = $userInfo['user_id'];
- } else {
- $user_id = $userInfo;
- }
-
- if (is_null($auth_time)) {
- $auth_time = time();
- }
-
- // userInfo is a scalar, and so this is the $user_id. Auth Time is null
- return array($user_id, $auth_time);
- }
-}
diff --git a/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php
deleted file mode 100644
index 0bd2f8391..000000000
--- a/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php
+++ /dev/null
@@ -1,29 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\ResponseType;
-
-use OAuth2\ResponseType\ResponseTypeInterface;
-
-interface IdTokenInterface extends ResponseTypeInterface
-{
- /**
- * Create the id token.
- *
- * If Authorization Code Flow is used, the id_token is generated when the
- * authorization code is issued, and later returned from the token endpoint
- * together with the access_token.
- * If the Implicit Flow is used, the token and id_token are generated and
- * returned together.
- *
- * @param string $client_id The client id.
- * @param string $user_id The user id.
- * @param string $nonce OPTIONAL The nonce.
- * @param string $userClaims OPTIONAL Claims about the user.
- * @param string $access_token OPTIONAL The access token, if known.
- *
- * @return string The ID Token represented as a JSON Web Token (JWT).
- *
- * @see http://openid.net/specs/openid-connect-core-1_0.html#IDToken
- */
- public function createIdToken($client_id, $userInfo, $nonce = null, $userClaims = null, $access_token = null);
-}
diff --git a/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenToken.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenToken.php
deleted file mode 100644
index f0c59799b..000000000
--- a/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenToken.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\ResponseType;
-
-use OAuth2\ResponseType\AccessTokenInterface;
-
-class IdTokenToken implements IdTokenTokenInterface
-{
- protected $accessToken;
- protected $idToken;
-
- public function __construct(AccessTokenInterface $accessToken, IdTokenInterface $idToken)
- {
- $this->accessToken = $accessToken;
- $this->idToken = $idToken;
- }
-
- public function getAuthorizeResponse($params, $user_id = null)
- {
- $result = $this->accessToken->getAuthorizeResponse($params, $user_id);
- $access_token = $result[1]['fragment']['access_token'];
- $id_token = $this->idToken->createIdToken($params['client_id'], $user_id, $params['nonce'], null, $access_token);
- $result[1]['fragment']['id_token'] = $id_token;
-
- return $result;
- }
-}
diff --git a/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php
deleted file mode 100644
index ac13e2032..000000000
--- a/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php
+++ /dev/null
@@ -1,9 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\ResponseType;
-
-use OAuth2\ResponseType\ResponseTypeInterface;
-
-interface IdTokenTokenInterface extends ResponseTypeInterface
-{
-}
diff --git a/library/oauth2/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php b/library/oauth2/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php
deleted file mode 100644
index 51dd867ec..000000000
--- a/library/oauth2/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\Storage;
-
-use OAuth2\Storage\AuthorizationCodeInterface as BaseAuthorizationCodeInterface;
-/**
- * Implement this interface to specify where the OAuth2 Server
- * should get/save authorization codes for the "Authorization Code"
- * grant type
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface
-{
- /**
- * Take the provided authorization code values and store them somewhere.
- *
- * This function should be the storage counterpart to getAuthCode().
- *
- * If storage fails for some reason, we're not currently checking for
- * any sort of success/failure, so you should bail out of the script
- * and provide a descriptive fail message.
- *
- * Required for OAuth2::GRANT_TYPE_AUTH_CODE.
- *
- * @param $code authorization code to be stored.
- * @param $client_id client identifier to be stored.
- * @param $user_id user identifier to be stored.
- * @param string $redirect_uri redirect URI(s) to be stored in a space-separated string.
- * @param int $expires expiration to be stored as a Unix timestamp.
- * @param string $scope OPTIONAL scopes to be stored in space-separated string.
- * @param string $id_token OPTIONAL the OpenID Connect id_token.
- *
- * @ingroup oauth2_section_4
- */
- public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null);
-}
diff --git a/library/oauth2/src/OAuth2/OpenID/Storage/UserClaimsInterface.php b/library/oauth2/src/OAuth2/OpenID/Storage/UserClaimsInterface.php
deleted file mode 100644
index f230bef9e..000000000
--- a/library/oauth2/src/OAuth2/OpenID/Storage/UserClaimsInterface.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\Storage;
-
-/**
- * Implement this interface to specify where the OAuth2 Server
- * should retrieve user claims for the OpenID Connect id_token.
- */
-interface UserClaimsInterface
-{
- // valid scope values to pass into the user claims API call
- const VALID_CLAIMS = 'profile email address phone';
-
- // fields returned for the claims above
- const PROFILE_CLAIM_VALUES = 'name family_name given_name middle_name nickname preferred_username profile picture website gender birthdate zoneinfo locale updated_at';
- const EMAIL_CLAIM_VALUES = 'email email_verified';
- const ADDRESS_CLAIM_VALUES = 'formatted street_address locality region postal_code country';
- const PHONE_CLAIM_VALUES = 'phone_number phone_number_verified';
-
- /**
- * Return claims about the provided user id.
- *
- * Groups of claims are returned based on the requested scopes. No group
- * is required, and no claim is required.
- *
- * @param $user_id
- * The id of the user for which claims should be returned.
- * @param $scope
- * The requested scope.
- * Scopes with matching claims: profile, email, address, phone.
- *
- * @return
- * An array in the claim => value format.
- *
- * @see http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims
- */
- public function getUserClaims($user_id, $scope);
-}
diff --git a/library/oauth2/src/OAuth2/Request.php b/library/oauth2/src/OAuth2/Request.php
deleted file mode 100644
index c92cee821..000000000
--- a/library/oauth2/src/OAuth2/Request.php
+++ /dev/null
@@ -1,213 +0,0 @@
-<?php
-
-namespace OAuth2;
-
-/**
- * OAuth2\Request
- * This class is taken from the Symfony2 Framework and is part of the Symfony package.
- * See Symfony\Component\HttpFoundation\Request (https://github.com/symfony/symfony)
- */
-class Request implements RequestInterface
-{
- public $attributes;
- public $request;
- public $query;
- public $server;
- public $files;
- public $cookies;
- public $headers;
- public $content;
-
- /**
- * Constructor.
- *
- * @param array $query The GET parameters
- * @param array $request The POST parameters
- * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
- * @param array $cookies The COOKIE parameters
- * @param array $files The FILES parameters
- * @param array $server The SERVER parameters
- * @param string $content The raw body data
- *
- * @api
- */
- public function __construct(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null, array $headers = null)
- {
- $this->initialize($query, $request, $attributes, $cookies, $files, $server, $content, $headers);
- }
-
- /**
- * Sets the parameters for this request.
- *
- * This method also re-initializes all properties.
- *
- * @param array $query The GET parameters
- * @param array $request The POST parameters
- * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
- * @param array $cookies The COOKIE parameters
- * @param array $files The FILES parameters
- * @param array $server The SERVER parameters
- * @param string $content The raw body data
- *
- * @api
- */
- public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null, array $headers = null)
- {
- $this->request = $request;
- $this->query = $query;
- $this->attributes = $attributes;
- $this->cookies = $cookies;
- $this->files = $files;
- $this->server = $server;
- $this->content = $content;
- $this->headers = is_null($headers) ? $this->getHeadersFromServer($this->server) : $headers;
- }
-
- public function query($name, $default = null)
- {
- return isset($this->query[$name]) ? $this->query[$name] : $default;
- }
-
- public function request($name, $default = null)
- {
- return isset($this->request[$name]) ? $this->request[$name] : $default;
- }
-
- public function server($name, $default = null)
- {
- return isset($this->server[$name]) ? $this->server[$name] : $default;
- }
-
- public function headers($name, $default = null)
- {
- $headers = array_change_key_case($this->headers);
- $name = strtolower($name);
-
- return isset($headers[$name]) ? $headers[$name] : $default;
- }
-
- public function getAllQueryParameters()
- {
- return $this->query;
- }
-
- /**
- * Returns the request body content.
- *
- * @param Boolean $asResource If true, a resource will be returned
- *
- * @return string|resource The request body content or a resource to read the body stream.
- */
- public function getContent($asResource = false)
- {
- if (false === $this->content || (true === $asResource && null !== $this->content)) {
- throw new \LogicException('getContent() can only be called once when using the resource return type.');
- }
-
- if (true === $asResource) {
- $this->content = false;
-
- return fopen('php://input', 'rb');
- }
-
- if (null === $this->content) {
- $this->content = file_get_contents('php://input');
- }
-
- return $this->content;
- }
-
- private function getHeadersFromServer($server)
- {
- $headers = array();
- foreach ($server as $key => $value) {
- if (0 === strpos($key, 'HTTP_')) {
- $headers[substr($key, 5)] = $value;
- }
- // CONTENT_* are not prefixed with HTTP_
- elseif (in_array($key, array('CONTENT_LENGTH', 'CONTENT_MD5', 'CONTENT_TYPE'))) {
- $headers[$key] = $value;
- }
- }
-
- if (isset($server['PHP_AUTH_USER'])) {
- $headers['PHP_AUTH_USER'] = $server['PHP_AUTH_USER'];
- $headers['PHP_AUTH_PW'] = isset($server['PHP_AUTH_PW']) ? $server['PHP_AUTH_PW'] : '';
- } else {
- /*
- * php-cgi under Apache does not pass HTTP Basic user/pass to PHP by default
- * For this workaround to work, add this line to your .htaccess file:
- * RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
- *
- * A sample .htaccess file:
- * RewriteEngine On
- * RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
- * RewriteCond %{REQUEST_FILENAME} !-f
- * RewriteRule ^(.*)$ app.php [QSA,L]
- */
-
- $authorizationHeader = null;
- if (isset($server['HTTP_AUTHORIZATION'])) {
- $authorizationHeader = $server['HTTP_AUTHORIZATION'];
- } elseif (isset($server['REDIRECT_HTTP_AUTHORIZATION'])) {
- $authorizationHeader = $server['REDIRECT_HTTP_AUTHORIZATION'];
- } elseif (function_exists('apache_request_headers')) {
- $requestHeaders = (array) apache_request_headers();
-
- // Server-side fix for bug in old Android versions (a nice side-effect of this fix means we don't care about capitalization for Authorization)
- $requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders));
-
- if (isset($requestHeaders['Authorization'])) {
- $authorizationHeader = trim($requestHeaders['Authorization']);
- }
- }
-
- if (null !== $authorizationHeader) {
- $headers['AUTHORIZATION'] = $authorizationHeader;
- // Decode AUTHORIZATION header into PHP_AUTH_USER and PHP_AUTH_PW when authorization header is basic
- if (0 === stripos($authorizationHeader, 'basic')) {
- $exploded = explode(':', base64_decode(substr($authorizationHeader, 6)));
- if (count($exploded) == 2) {
- list($headers['PHP_AUTH_USER'], $headers['PHP_AUTH_PW']) = $exploded;
- }
- }
- }
- }
-
- // PHP_AUTH_USER/PHP_AUTH_PW
- if (isset($headers['PHP_AUTH_USER'])) {
- $headers['AUTHORIZATION'] = 'Basic '.base64_encode($headers['PHP_AUTH_USER'].':'.$headers['PHP_AUTH_PW']);
- }
-
- return $headers;
- }
-
- /**
- * Creates a new request with values from PHP's super globals.
- *
- * @return Request A new request
- *
- * @api
- */
- public static function createFromGlobals()
- {
- $class = get_called_class();
- $request = new $class($_GET, $_POST, array(), $_COOKIE, $_FILES, $_SERVER);
-
- $contentType = $request->server('CONTENT_TYPE', '');
- $requestMethod = $request->server('REQUEST_METHOD', 'GET');
- if (0 === strpos($contentType, 'application/x-www-form-urlencoded')
- && in_array(strtoupper($requestMethod), array('PUT', 'DELETE'))
- ) {
- parse_str($request->getContent(), $data);
- $request->request = $data;
- } elseif (0 === strpos($contentType, 'application/json')
- && in_array(strtoupper($requestMethod), array('POST', 'PUT', 'DELETE'))
- ) {
- $data = json_decode($request->getContent(), true);
- $request->request = $data;
- }
-
- return $request;
- }
-}
diff --git a/library/oauth2/src/OAuth2/RequestInterface.php b/library/oauth2/src/OAuth2/RequestInterface.php
deleted file mode 100644
index 8a70d5fad..000000000
--- a/library/oauth2/src/OAuth2/RequestInterface.php
+++ /dev/null
@@ -1,16 +0,0 @@
-<?php
-
-namespace OAuth2;
-
-interface RequestInterface
-{
- public function query($name, $default = null);
-
- public function request($name, $default = null);
-
- public function server($name, $default = null);
-
- public function headers($name, $default = null);
-
- public function getAllQueryParameters();
-}
diff --git a/library/oauth2/src/OAuth2/Response.php b/library/oauth2/src/OAuth2/Response.php
deleted file mode 100644
index d8eabe79e..000000000
--- a/library/oauth2/src/OAuth2/Response.php
+++ /dev/null
@@ -1,369 +0,0 @@
-<?php
-
-namespace OAuth2;
-
-/**
- * Class to handle OAuth2 Responses in a graceful way. Use this interface
- * to output the proper OAuth2 responses.
- *
- * @see OAuth2\ResponseInterface
- *
- * This class borrows heavily from the Symfony2 Framework and is part of the symfony package
- * @see Symfony\Component\HttpFoundation\Request (https://github.com/symfony/symfony)
- */
-class Response implements ResponseInterface
-{
- public $version;
- protected $statusCode = 200;
- protected $statusText;
- protected $parameters = array();
- protected $httpHeaders = array();
-
- public static $statusTexts = array(
- 100 => 'Continue',
- 101 => 'Switching Protocols',
- 200 => 'OK',
- 201 => 'Created',
- 202 => 'Accepted',
- 203 => 'Non-Authoritative Information',
- 204 => 'No Content',
- 205 => 'Reset Content',
- 206 => 'Partial Content',
- 300 => 'Multiple Choices',
- 301 => 'Moved Permanently',
- 302 => 'Found',
- 303 => 'See Other',
- 304 => 'Not Modified',
- 305 => 'Use Proxy',
- 307 => 'Temporary Redirect',
- 400 => 'Bad Request',
- 401 => 'Unauthorized',
- 402 => 'Payment Required',
- 403 => 'Forbidden',
- 404 => 'Not Found',
- 405 => 'Method Not Allowed',
- 406 => 'Not Acceptable',
- 407 => 'Proxy Authentication Required',
- 408 => 'Request Timeout',
- 409 => 'Conflict',
- 410 => 'Gone',
- 411 => 'Length Required',
- 412 => 'Precondition Failed',
- 413 => 'Request Entity Too Large',
- 414 => 'Request-URI Too Long',
- 415 => 'Unsupported Media Type',
- 416 => 'Requested Range Not Satisfiable',
- 417 => 'Expectation Failed',
- 418 => 'I\'m a teapot',
- 500 => 'Internal Server Error',
- 501 => 'Not Implemented',
- 502 => 'Bad Gateway',
- 503 => 'Service Unavailable',
- 504 => 'Gateway Timeout',
- 505 => 'HTTP Version Not Supported',
- );
-
- public function __construct($parameters = array(), $statusCode = 200, $headers = array())
- {
- $this->setParameters($parameters);
- $this->setStatusCode($statusCode);
- $this->setHttpHeaders($headers);
- $this->version = '1.1';
- }
-
- /**
- * Converts the response object to string containing all headers and the response content.
- *
- * @return string The response with headers and content
- */
- public function __toString()
- {
- $headers = array();
- foreach ($this->httpHeaders as $name => $value) {
- $headers[$name] = (array) $value;
- }
-
- return
- sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)."\r\n".
- $this->getHttpHeadersAsString($headers)."\r\n".
- $this->getResponseBody();
- }
-
- /**
- * Returns the build header line.
- *
- * @param string $name The header name
- * @param string $value The header value
- *
- * @return string The built header line
- */
- protected function buildHeader($name, $value)
- {
- return sprintf("%s: %s\n", $name, $value);
- }
-
- public function getStatusCode()
- {
- return $this->statusCode;
- }
-
- public function setStatusCode($statusCode, $text = null)
- {
- $this->statusCode = (int) $statusCode;
- if ($this->isInvalid()) {
- throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $statusCode));
- }
-
- $this->statusText = false === $text ? '' : (null === $text ? self::$statusTexts[$this->statusCode] : $text);
- }
-
- public function getStatusText()
- {
- return $this->statusText;
- }
-
- public function getParameters()
- {
- return $this->parameters;
- }
-
- public function setParameters(array $parameters)
- {
- $this->parameters = $parameters;
- }
-
- public function addParameters(array $parameters)
- {
- $this->parameters = array_merge($this->parameters, $parameters);
- }
-
- public function getParameter($name, $default = null)
- {
- return isset($this->parameters[$name]) ? $this->parameters[$name] : $default;
- }
-
- public function setParameter($name, $value)
- {
- $this->parameters[$name] = $value;
- }
-
- public function setHttpHeaders(array $httpHeaders)
- {
- $this->httpHeaders = $httpHeaders;
- }
-
- public function setHttpHeader($name, $value)
- {
- $this->httpHeaders[$name] = $value;
- }
-
- public function addHttpHeaders(array $httpHeaders)
- {
- $this->httpHeaders = array_merge($this->httpHeaders, $httpHeaders);
- }
-
- public function getHttpHeaders()
- {
- return $this->httpHeaders;
- }
-
- public function getHttpHeader($name, $default = null)
- {
- return isset($this->httpHeaders[$name]) ? $this->httpHeaders[$name] : $default;
- }
-
- public function getResponseBody($format = 'json')
- {
- switch ($format) {
- case 'json':
- return json_encode($this->parameters);
- case 'xml':
- // this only works for single-level arrays
- $xml = new \SimpleXMLElement('<response/>');
- foreach ($this->parameters as $key => $param) {
- $xml->addChild($key, $param);
- }
-
- return $xml->asXML();
- }
-
- throw new \InvalidArgumentException(sprintf('The format %s is not supported', $format));
-
- }
-
- public function send($format = 'json')
- {
- // headers have already been sent by the developer
- if (headers_sent()) {
- return;
- }
-
- switch ($format) {
- case 'json':
- $this->setHttpHeader('Content-Type', 'application/json');
- break;
- case 'xml':
- $this->setHttpHeader('Content-Type', 'text/xml');
- break;
- }
- // status
- header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText));
-
- foreach ($this->getHttpHeaders() as $name => $header) {
- header(sprintf('%s: %s', $name, $header));
- }
- echo $this->getResponseBody($format);
- }
-
- public function setError($statusCode, $error, $errorDescription = null, $errorUri = null)
- {
- $parameters = array(
- 'error' => $error,
- 'error_description' => $errorDescription,
- );
-
- if (!is_null($errorUri)) {
- if (strlen($errorUri) > 0 && $errorUri[0] == '#') {
- // we are referencing an oauth bookmark (for brevity)
- $errorUri = 'http://tools.ietf.org/html/rfc6749' . $errorUri;
- }
- $parameters['error_uri'] = $errorUri;
- }
-
- $httpHeaders = array(
- 'Cache-Control' => 'no-store'
- );
-
- $this->setStatusCode($statusCode);
- $this->addParameters($parameters);
- $this->addHttpHeaders($httpHeaders);
-
- if (!$this->isClientError() && !$this->isServerError()) {
- throw new \InvalidArgumentException(sprintf('The HTTP status code is not an error ("%s" given).', $statusCode));
- }
- }
-
- public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null)
- {
- if (empty($url)) {
- throw new \InvalidArgumentException('Cannot redirect to an empty URL.');
- }
-
- $parameters = array();
-
- if (!is_null($state)) {
- $parameters['state'] = $state;
- }
-
- if (!is_null($error)) {
- $this->setError(400, $error, $errorDescription, $errorUri);
- }
- $this->setStatusCode($statusCode);
- $this->addParameters($parameters);
-
- if (count($this->parameters) > 0) {
- // add parameters to URL redirection
- $parts = parse_url($url);
- $sep = isset($parts['query']) && count($parts['query']) > 0 ? '&' : '?';
- $url .= $sep . http_build_query($this->parameters);
- }
-
- $this->addHttpHeaders(array('Location' => $url));
-
- if (!$this->isRedirection()) {
- throw new \InvalidArgumentException(sprintf('The HTTP status code is not a redirect ("%s" given).', $statusCode));
- }
- }
-
- // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
- /**
- * @return Boolean
- *
- * @api
- */
- public function isInvalid()
- {
- return $this->statusCode < 100 || $this->statusCode >= 600;
- }
-
- /**
- * @return Boolean
- *
- * @api
- */
- public function isInformational()
- {
- return $this->statusCode >= 100 && $this->statusCode < 200;
- }
-
- /**
- * @return Boolean
- *
- * @api
- */
- public function isSuccessful()
- {
- return $this->statusCode >= 200 && $this->statusCode < 300;
- }
-
- /**
- * @return Boolean
- *
- * @api
- */
- public function isRedirection()
- {
- return $this->statusCode >= 300 && $this->statusCode < 400;
- }
-
- /**
- * @return Boolean
- *
- * @api
- */
- public function isClientError()
- {
- return $this->statusCode >= 400 && $this->statusCode < 500;
- }
-
- /**
- * @return Boolean
- *
- * @api
- */
- public function isServerError()
- {
- return $this->statusCode >= 500 && $this->statusCode < 600;
- }
-
- /*
- * Functions from Symfony2 HttpFoundation - output pretty header
- */
- private function getHttpHeadersAsString($headers)
- {
- if (count($headers) == 0) {
- return '';
- }
-
- $max = max(array_map('strlen', array_keys($headers))) + 1;
- $content = '';
- ksort($headers);
- foreach ($headers as $name => $values) {
- foreach ($values as $value) {
- $content .= sprintf("%-{$max}s %s\r\n", $this->beautifyHeaderName($name).':', $value);
- }
- }
-
- return $content;
- }
-
- private function beautifyHeaderName($name)
- {
- return preg_replace_callback('/\-(.)/', array($this, 'beautifyCallback'), ucfirst($name));
- }
-
- private function beautifyCallback($match)
- {
- return '-'.strtoupper($match[1]);
- }
-}
diff --git a/library/oauth2/src/OAuth2/ResponseInterface.php b/library/oauth2/src/OAuth2/ResponseInterface.php
deleted file mode 100644
index c99b5f7d1..000000000
--- a/library/oauth2/src/OAuth2/ResponseInterface.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-
-namespace OAuth2;
-
-/**
- * Interface which represents an object response. Meant to handle and display the proper OAuth2 Responses
- * for errors and successes
- *
- * @see OAuth2\Response
- */
-interface ResponseInterface
-{
- public function addParameters(array $parameters);
-
- public function addHttpHeaders(array $httpHeaders);
-
- public function setStatusCode($statusCode);
-
- public function setError($statusCode, $name, $description = null, $uri = null);
-
- public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null);
-
- public function getParameter($name);
-}
diff --git a/library/oauth2/src/OAuth2/ResponseType/AccessToken.php b/library/oauth2/src/OAuth2/ResponseType/AccessToken.php
deleted file mode 100644
index b235ad0c5..000000000
--- a/library/oauth2/src/OAuth2/ResponseType/AccessToken.php
+++ /dev/null
@@ -1,194 +0,0 @@
-<?php
-
-namespace OAuth2\ResponseType;
-
-use OAuth2\Storage\AccessTokenInterface as AccessTokenStorageInterface;
-use OAuth2\Storage\RefreshTokenInterface;
-
-/**
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-class AccessToken implements AccessTokenInterface
-{
- protected $tokenStorage;
- protected $refreshStorage;
- protected $config;
-
- /**
- * @param OAuth2\Storage\AccessTokenInterface $tokenStorage REQUIRED Storage class for saving access token information
- * @param OAuth2\Storage\RefreshTokenInterface $refreshStorage OPTIONAL Storage class for saving refresh token information
- * @param array $config OPTIONAL Configuration options for the server
- * <code>
- * $config = array(
- * 'token_type' => 'bearer', // token type identifier
- * 'access_lifetime' => 3600, // time before access token expires
- * 'refresh_token_lifetime' => 1209600, // time before refresh token expires
- * );
- * </endcode>
- */
- public function __construct(AccessTokenStorageInterface $tokenStorage, RefreshTokenInterface $refreshStorage = null, array $config = array())
- {
- $this->tokenStorage = $tokenStorage;
- $this->refreshStorage = $refreshStorage;
-
- $this->config = array_merge(array(
- 'token_type' => 'bearer',
- 'access_lifetime' => 3600,
- 'refresh_token_lifetime' => 1209600,
- ), $config);
- }
-
- public function getAuthorizeResponse($params, $user_id = null)
- {
- // build the URL to redirect to
- $result = array('query' => array());
-
- $params += array('scope' => null, 'state' => null);
-
- /*
- * a refresh token MUST NOT be included in the fragment
- *
- * @see http://tools.ietf.org/html/rfc6749#section-4.2.2
- */
- $includeRefreshToken = false;
- $result["fragment"] = $this->createAccessToken($params['client_id'], $user_id, $params['scope'], $includeRefreshToken);
-
- if (isset($params['state'])) {
- $result["fragment"]["state"] = $params['state'];
- }
-
- return array($params['redirect_uri'], $result);
- }
-
- /**
- * Handle the creation of access token, also issue refresh token if supported / desirable.
- *
- * @param $client_id client identifier related to the access token.
- * @param $user_id user ID associated with the access token
- * @param $scope OPTIONAL scopes to be stored in space-separated string.
- * @param bool $includeRefreshToken if true, a new refresh_token will be added to the response
- *
- * @see http://tools.ietf.org/html/rfc6749#section-5
- * @ingroup oauth2_section_5
- */
- public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true)
- {
- $token = array(
- "access_token" => $this->generateAccessToken(),
- "expires_in" => $this->config['access_lifetime'],
- "token_type" => $this->config['token_type'],
- "scope" => $scope
- );
-
- $this->tokenStorage->setAccessToken($token["access_token"], $client_id, $user_id, $this->config['access_lifetime'] ? time() + $this->config['access_lifetime'] : null, $scope);
-
- /*
- * Issue a refresh token also, if we support them
- *
- * Refresh Tokens are considered supported if an instance of OAuth2\Storage\RefreshTokenInterface
- * is supplied in the constructor
- */
- if ($includeRefreshToken && $this->refreshStorage) {
- $token["refresh_token"] = $this->generateRefreshToken();
- $expires = 0;
- if ($this->config['refresh_token_lifetime'] > 0) {
- $expires = time() + $this->config['refresh_token_lifetime'];
- }
- $this->refreshStorage->setRefreshToken($token['refresh_token'], $client_id, $user_id, $expires, $scope);
- }
-
- return $token;
- }
-
- /**
- * Generates an unique access token.
- *
- * Implementing classes may want to override this function to implement
- * other access token generation schemes.
- *
- * @return
- * An unique access token.
- *
- * @ingroup oauth2_section_4
- */
- protected function generateAccessToken()
- {
- if (function_exists('mcrypt_create_iv')) {
- $randomData = mcrypt_create_iv(20, MCRYPT_DEV_URANDOM);
- if ($randomData !== false && strlen($randomData) === 20) {
- return bin2hex($randomData);
- }
- }
- if (function_exists('openssl_random_pseudo_bytes')) {
- $randomData = openssl_random_pseudo_bytes(20);
- if ($randomData !== false && strlen($randomData) === 20) {
- return bin2hex($randomData);
- }
- }
- if (@file_exists('/dev/urandom')) { // Get 100 bytes of random data
- $randomData = file_get_contents('/dev/urandom', false, null, 0, 20);
- if ($randomData !== false && strlen($randomData) === 20) {
- return bin2hex($randomData);
- }
- }
- // Last resort which you probably should just get rid of:
- $randomData = mt_rand() . mt_rand() . mt_rand() . mt_rand() . microtime(true) . uniqid(mt_rand(), true);
-
- return substr(hash('sha512', $randomData), 0, 40);
- }
-
- /**
- * Generates an unique refresh token
- *
- * Implementing classes may want to override this function to implement
- * other refresh token generation schemes.
- *
- * @return
- * An unique refresh.
- *
- * @ingroup oauth2_section_4
- * @see OAuth2::generateAccessToken()
- */
- protected function generateRefreshToken()
- {
- return $this->generateAccessToken(); // let's reuse the same scheme for token generation
- }
-
- /**
- * Handle the revoking of refresh tokens, and access tokens if supported / desirable
- * RFC7009 specifies that "If the server is unable to locate the token using
- * the given hint, it MUST extend its search across all of its supported token types"
- *
- * @param $token
- * @param null $tokenTypeHint
- * @return boolean
- */
- public function revokeToken($token, $tokenTypeHint = null)
- {
- if ($tokenTypeHint == 'refresh_token') {
- if ($this->refreshStorage && $revoked = $this->refreshStorage->unsetRefreshToken($token)) {
- return true;
- }
- }
-
- /** @TODO remove in v2 */
- if (!method_exists($this->tokenStorage, 'unsetAccessToken')) {
- throw new \RuntimeException(
- sprintf('Token storage %s must implement unsetAccessToken method', get_class($this->tokenStorage)
- ));
- }
-
- $revoked = $this->tokenStorage->unsetAccessToken($token);
-
- // if a typehint is supplied and fails, try other storages
- // @see https://tools.ietf.org/html/rfc7009#section-2.1
- if (!$revoked && $tokenTypeHint != 'refresh_token') {
- if ($this->refreshStorage) {
- $revoked = $this->refreshStorage->unsetRefreshToken($token);
- }
- }
-
- return $revoked;
- }
-}
diff --git a/library/oauth2/src/OAuth2/ResponseType/AccessTokenInterface.php b/library/oauth2/src/OAuth2/ResponseType/AccessTokenInterface.php
deleted file mode 100644
index 4bd3928d8..000000000
--- a/library/oauth2/src/OAuth2/ResponseType/AccessTokenInterface.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-namespace OAuth2\ResponseType;
-
-/**
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-interface AccessTokenInterface extends ResponseTypeInterface
-{
- /**
- * Handle the creation of access token, also issue refresh token if supported / desirable.
- *
- * @param $client_id client identifier related to the access token.
- * @param $user_id user ID associated with the access token
- * @param $scope OPTONAL scopes to be stored in space-separated string.
- * @param bool $includeRefreshToken if true, a new refresh_token will be added to the response
- *
- * @see http://tools.ietf.org/html/rfc6749#section-5
- * @ingroup oauth2_section_5
- */
- public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true);
-
- /**
- * Handle the revoking of refresh tokens, and access tokens if supported / desirable
- *
- * @param $token
- * @param $tokenTypeHint
- * @return mixed
- *
- * @todo v2.0 include this method in interface. Omitted to maintain BC in v1.x
- */
- //public function revokeToken($token, $tokenTypeHint);
-}
diff --git a/library/oauth2/src/OAuth2/ResponseType/AuthorizationCode.php b/library/oauth2/src/OAuth2/ResponseType/AuthorizationCode.php
deleted file mode 100644
index 6a305fd75..000000000
--- a/library/oauth2/src/OAuth2/ResponseType/AuthorizationCode.php
+++ /dev/null
@@ -1,100 +0,0 @@
-<?php
-
-namespace OAuth2\ResponseType;
-
-use OAuth2\Storage\AuthorizationCodeInterface as AuthorizationCodeStorageInterface;
-
-/**
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-class AuthorizationCode implements AuthorizationCodeInterface
-{
- protected $storage;
- protected $config;
-
- public function __construct(AuthorizationCodeStorageInterface $storage, array $config = array())
- {
- $this->storage = $storage;
- $this->config = array_merge(array(
- 'enforce_redirect' => false,
- 'auth_code_lifetime' => 30,
- ), $config);
- }
-
- public function getAuthorizeResponse($params, $user_id = null)
- {
- // build the URL to redirect to
- $result = array('query' => array());
-
- $params += array('scope' => null, 'state' => null);
-
- $result['query']['code'] = $this->createAuthorizationCode($params['client_id'], $user_id, $params['redirect_uri'], $params['scope']);
-
- if (isset($params['state'])) {
- $result['query']['state'] = $params['state'];
- }
-
- return array($params['redirect_uri'], $result);
- }
-
- /**
- * Handle the creation of the authorization code.
- *
- * @param $client_id
- * Client identifier related to the authorization code
- * @param $user_id
- * User ID associated with the authorization code
- * @param $redirect_uri
- * An absolute URI to which the authorization server will redirect the
- * user-agent to when the end-user authorization step is completed.
- * @param $scope
- * (optional) Scopes to be stored in space-separated string.
- *
- * @see http://tools.ietf.org/html/rfc6749#section-4
- * @ingroup oauth2_section_4
- */
- public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null)
- {
- $code = $this->generateAuthorizationCode();
- $this->storage->setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, time() + $this->config['auth_code_lifetime'], $scope);
-
- return $code;
- }
-
- /**
- * @return
- * TRUE if the grant type requires a redirect_uri, FALSE if not
- */
- public function enforceRedirect()
- {
- return $this->config['enforce_redirect'];
- }
-
- /**
- * Generates an unique auth code.
- *
- * Implementing classes may want to override this function to implement
- * other auth code generation schemes.
- *
- * @return
- * An unique auth code.
- *
- * @ingroup oauth2_section_4
- */
- protected function generateAuthorizationCode()
- {
- $tokenLen = 40;
- if (function_exists('mcrypt_create_iv')) {
- $randomData = mcrypt_create_iv(100, MCRYPT_DEV_URANDOM);
- } elseif (function_exists('openssl_random_pseudo_bytes')) {
- $randomData = openssl_random_pseudo_bytes(100);
- } elseif (@file_exists('/dev/urandom')) { // Get 100 bytes of random data
- $randomData = file_get_contents('/dev/urandom', false, null, 0, 100) . uniqid(mt_rand(), true);
- } else {
- $randomData = mt_rand() . mt_rand() . mt_rand() . mt_rand() . microtime(true) . uniqid(mt_rand(), true);
- }
-
- return substr(hash('sha512', $randomData), 0, $tokenLen);
- }
-}
diff --git a/library/oauth2/src/OAuth2/ResponseType/AuthorizationCodeInterface.php b/library/oauth2/src/OAuth2/ResponseType/AuthorizationCodeInterface.php
deleted file mode 100644
index df777e221..000000000
--- a/library/oauth2/src/OAuth2/ResponseType/AuthorizationCodeInterface.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-namespace OAuth2\ResponseType;
-
-/**
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-interface AuthorizationCodeInterface extends ResponseTypeInterface
-{
- /**
- * @return
- * TRUE if the grant type requires a redirect_uri, FALSE if not
- */
- public function enforceRedirect();
-
- /**
- * Handle the creation of the authorization code.
- *
- * @param $client_id client identifier related to the authorization code
- * @param $user_id user id associated with the authorization code
- * @param $redirect_uri an absolute URI to which the authorization server will redirect the
- * user-agent to when the end-user authorization step is completed.
- * @param $scope OPTIONAL scopes to be stored in space-separated string.
- *
- * @see http://tools.ietf.org/html/rfc6749#section-4
- * @ingroup oauth2_section_4
- */
- public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null);
-}
diff --git a/library/oauth2/src/OAuth2/ResponseType/JwtAccessToken.php b/library/oauth2/src/OAuth2/ResponseType/JwtAccessToken.php
deleted file mode 100644
index 3942fe41e..000000000
--- a/library/oauth2/src/OAuth2/ResponseType/JwtAccessToken.php
+++ /dev/null
@@ -1,124 +0,0 @@
-<?php
-
-namespace OAuth2\ResponseType;
-
-use OAuth2\Encryption\EncryptionInterface;
-use OAuth2\Encryption\Jwt;
-use OAuth2\Storage\AccessTokenInterface as AccessTokenStorageInterface;
-use OAuth2\Storage\RefreshTokenInterface;
-use OAuth2\Storage\PublicKeyInterface;
-use OAuth2\Storage\Memory;
-
-/**
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-class JwtAccessToken extends AccessToken
-{
- protected $publicKeyStorage;
- protected $encryptionUtil;
-
- /**
- * @param $config
- * - store_encrypted_token_string (bool true)
- * whether the entire encrypted string is stored,
- * or just the token ID is stored
- */
- public function __construct(PublicKeyInterface $publicKeyStorage = null, AccessTokenStorageInterface $tokenStorage = null, RefreshTokenInterface $refreshStorage = null, array $config = array(), EncryptionInterface $encryptionUtil = null)
- {
- $this->publicKeyStorage = $publicKeyStorage;
- $config = array_merge(array(
- 'store_encrypted_token_string' => true,
- 'issuer' => ''
- ), $config);
- if (is_null($tokenStorage)) {
- // a pass-thru, so we can call the parent constructor
- $tokenStorage = new Memory();
- }
- if (is_null($encryptionUtil)) {
- $encryptionUtil = new Jwt();
- }
- $this->encryptionUtil = $encryptionUtil;
- parent::__construct($tokenStorage, $refreshStorage, $config);
- }
-
- /**
- * Handle the creation of access token, also issue refresh token if supported / desirable.
- *
- * @param $client_id
- * Client identifier related to the access token.
- * @param $user_id
- * User ID associated with the access token
- * @param $scope
- * (optional) Scopes to be stored in space-separated string.
- * @param bool $includeRefreshToken
- * If true, a new refresh_token will be added to the response
- *
- * @see http://tools.ietf.org/html/rfc6749#section-5
- * @ingroup oauth2_section_5
- */
- public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true)
- {
- // token to encrypt
- $expires = time() + $this->config['access_lifetime'];
- $id = $this->generateAccessToken();
- $jwtAccessToken = array(
- 'id' => $id, // for BC (see #591)
- 'jti' => $id,
- 'iss' => $this->config['issuer'],
- 'aud' => $client_id,
- 'sub' => $user_id,
- 'exp' => $expires,
- 'iat' => time(),
- 'token_type' => $this->config['token_type'],
- 'scope' => $scope
- );
-
- /*
- * Encode the token data into a single access_token string
- */
- $access_token = $this->encodeToken($jwtAccessToken, $client_id);
-
- /*
- * Save the token to a secondary storage. This is implemented on the
- * OAuth2\Storage\JwtAccessToken side, and will not actually store anything,
- * if no secondary storage has been supplied
- */
- $token_to_store = $this->config['store_encrypted_token_string'] ? $access_token : $jwtAccessToken['id'];
- $this->tokenStorage->setAccessToken($token_to_store, $client_id, $user_id, $this->config['access_lifetime'] ? time() + $this->config['access_lifetime'] : null, $scope);
-
- // token to return to the client
- $token = array(
- 'access_token' => $access_token,
- 'expires_in' => $this->config['access_lifetime'],
- 'token_type' => $this->config['token_type'],
- 'scope' => $scope
- );
-
- /*
- * Issue a refresh token also, if we support them
- *
- * Refresh Tokens are considered supported if an instance of OAuth2\Storage\RefreshTokenInterface
- * is supplied in the constructor
- */
- if ($includeRefreshToken && $this->refreshStorage) {
- $refresh_token = $this->generateRefreshToken();
- $expires = 0;
- if ($this->config['refresh_token_lifetime'] > 0) {
- $expires = time() + $this->config['refresh_token_lifetime'];
- }
- $this->refreshStorage->setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope);
- $token['refresh_token'] = $refresh_token;
- }
-
- return $token;
- }
-
- protected function encodeToken(array $token, $client_id = null)
- {
- $private_key = $this->publicKeyStorage->getPrivateKey($client_id);
- $algorithm = $this->publicKeyStorage->getEncryptionAlgorithm($client_id);
-
- return $this->encryptionUtil->encode($token, $private_key, $algorithm);
- }
-}
diff --git a/library/oauth2/src/OAuth2/ResponseType/ResponseTypeInterface.php b/library/oauth2/src/OAuth2/ResponseType/ResponseTypeInterface.php
deleted file mode 100644
index f8e26a5b0..000000000
--- a/library/oauth2/src/OAuth2/ResponseType/ResponseTypeInterface.php
+++ /dev/null
@@ -1,8 +0,0 @@
-<?php
-
-namespace OAuth2\ResponseType;
-
-interface ResponseTypeInterface
-{
- public function getAuthorizeResponse($params, $user_id = null);
-}
diff --git a/library/oauth2/src/OAuth2/Scope.php b/library/oauth2/src/OAuth2/Scope.php
deleted file mode 100644
index c44350bfd..000000000
--- a/library/oauth2/src/OAuth2/Scope.php
+++ /dev/null
@@ -1,103 +0,0 @@
-<?php
-
-namespace OAuth2;
-
-use OAuth2\Storage\Memory;
-use OAuth2\Storage\ScopeInterface as ScopeStorageInterface;
-
-/**
-* @see OAuth2\ScopeInterface
-*/
-class Scope implements ScopeInterface
-{
- protected $storage;
-
- /**
- * @param mixed @storage
- * Either an array of supported scopes, or an instance of OAuth2\Storage\ScopeInterface
- */
- public function __construct($storage = null)
- {
- if (is_null($storage) || is_array($storage)) {
- $storage = new Memory((array) $storage);
- }
-
- if (!$storage instanceof ScopeStorageInterface) {
- throw new \InvalidArgumentException("Argument 1 to OAuth2\Scope must be null, an array, or instance of OAuth2\Storage\ScopeInterface");
- }
-
- $this->storage = $storage;
- }
-
- /**
- * Check if everything in required scope is contained in available scope.
- *
- * @param $required_scope
- * A space-separated string of scopes.
- *
- * @return
- * TRUE if everything in required scope is contained in available scope,
- * and FALSE if it isn't.
- *
- * @see http://tools.ietf.org/html/rfc6749#section-7
- *
- * @ingroup oauth2_section_7
- */
- public function checkScope($required_scope, $available_scope)
- {
- $required_scope = explode(' ', trim($required_scope));
- $available_scope = explode(' ', trim($available_scope));
-
- return (count(array_diff($required_scope, $available_scope)) == 0);
- }
-
- /**
- * Check if the provided scope exists in storage.
- *
- * @param $scope
- * A space-separated string of scopes.
- *
- * @return
- * TRUE if it exists, FALSE otherwise.
- */
- public function scopeExists($scope)
- {
- // Check reserved scopes first.
- $scope = explode(' ', trim($scope));
- $reservedScope = $this->getReservedScopes();
- $nonReservedScopes = array_diff($scope, $reservedScope);
- if (count($nonReservedScopes) == 0) {
- return true;
- } else {
- // Check the storage for non-reserved scopes.
- $nonReservedScopes = implode(' ', $nonReservedScopes);
-
- return $this->storage->scopeExists($nonReservedScopes);
- }
- }
-
- public function getScopeFromRequest(RequestInterface $request)
- {
- // "scope" is valid if passed in either POST or QUERY
- return $request->request('scope', $request->query('scope'));
- }
-
- public function getDefaultScope($client_id = null)
- {
- return $this->storage->getDefaultScope($client_id);
- }
-
- /**
- * Get reserved scopes needed by the server.
- *
- * In case OpenID Connect is used, these scopes must include:
- * 'openid', offline_access'.
- *
- * @return
- * An array of reserved scopes.
- */
- public function getReservedScopes()
- {
- return array('openid', 'offline_access');
- }
-}
diff --git a/library/oauth2/src/OAuth2/ScopeInterface.php b/library/oauth2/src/OAuth2/ScopeInterface.php
deleted file mode 100644
index 5b60f9aee..000000000
--- a/library/oauth2/src/OAuth2/ScopeInterface.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-
-namespace OAuth2;
-
-use OAuth2\Storage\ScopeInterface as ScopeStorageInterface;
-
-/**
- * Class to handle scope implementation logic
- *
- * @see OAuth2\Storage\ScopeInterface
- */
-interface ScopeInterface extends ScopeStorageInterface
-{
- /**
- * Check if everything in required scope is contained in available scope.
- *
- * @param $required_scope
- * A space-separated string of scopes.
- *
- * @return
- * TRUE if everything in required scope is contained in available scope,
- * and FALSE if it isn't.
- *
- * @see http://tools.ietf.org/html/rfc6749#section-7
- *
- * @ingroup oauth2_section_7
- */
- public function checkScope($required_scope, $available_scope);
-
- /**
- * Return scope info from request
- *
- * @param OAuth2\RequestInterface
- * Request object to check
- *
- * @return
- * string representation of requested scope
- */
- public function getScopeFromRequest(RequestInterface $request);
-}
diff --git a/library/oauth2/src/OAuth2/Server.php b/library/oauth2/src/OAuth2/Server.php
deleted file mode 100644
index 171a4f069..000000000
--- a/library/oauth2/src/OAuth2/Server.php
+++ /dev/null
@@ -1,832 +0,0 @@
-<?php
-
-namespace OAuth2;
-
-use OAuth2\Controller\ResourceControllerInterface;
-use OAuth2\Controller\ResourceController;
-use OAuth2\OpenID\Controller\UserInfoControllerInterface;
-use OAuth2\OpenID\Controller\UserInfoController;
-use OAuth2\OpenID\Controller\AuthorizeController as OpenIDAuthorizeController;
-use OAuth2\OpenID\ResponseType\AuthorizationCode as OpenIDAuthorizationCodeResponseType;
-use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
-use OAuth2\OpenID\GrantType\AuthorizationCode as OpenIDAuthorizationCodeGrantType;
-use OAuth2\Controller\AuthorizeControllerInterface;
-use OAuth2\Controller\AuthorizeController;
-use OAuth2\Controller\TokenControllerInterface;
-use OAuth2\Controller\TokenController;
-use OAuth2\ClientAssertionType\ClientAssertionTypeInterface;
-use OAuth2\ClientAssertionType\HttpBasic;
-use OAuth2\ResponseType\ResponseTypeInterface;
-use OAuth2\ResponseType\AuthorizationCode as AuthorizationCodeResponseType;
-use OAuth2\ResponseType\AccessToken;
-use OAuth2\ResponseType\JwtAccessToken;
-use OAuth2\OpenID\ResponseType\CodeIdToken;
-use OAuth2\OpenID\ResponseType\IdToken;
-use OAuth2\OpenID\ResponseType\IdTokenToken;
-use OAuth2\TokenType\TokenTypeInterface;
-use OAuth2\TokenType\Bearer;
-use OAuth2\GrantType\GrantTypeInterface;
-use OAuth2\GrantType\UserCredentials;
-use OAuth2\GrantType\ClientCredentials;
-use OAuth2\GrantType\RefreshToken;
-use OAuth2\GrantType\AuthorizationCode;
-use OAuth2\Storage\JwtAccessToken as JwtAccessTokenStorage;
-use OAuth2\Storage\JwtAccessTokenInterface;
-
-/**
-* Server class for OAuth2
-* This class serves as a convience class which wraps the other Controller classes
-*
-* @see OAuth2\Controller\ResourceController
-* @see OAuth2\Controller\AuthorizeController
-* @see OAuth2\Controller\TokenController
-*/
-class Server implements ResourceControllerInterface,
- AuthorizeControllerInterface,
- TokenControllerInterface,
- UserInfoControllerInterface
-{
- // misc properties
- protected $response;
- protected $config;
- protected $storages;
-
- // servers
- protected $authorizeController;
- protected $tokenController;
- protected $resourceController;
- protected $userInfoController;
-
- // config classes
- protected $grantTypes;
- protected $responseTypes;
- protected $tokenType;
- protected $scopeUtil;
- protected $clientAssertionType;
-
- protected $storageMap = array(
- 'access_token' => 'OAuth2\Storage\AccessTokenInterface',
- 'authorization_code' => 'OAuth2\Storage\AuthorizationCodeInterface',
- 'client_credentials' => 'OAuth2\Storage\ClientCredentialsInterface',
- 'client' => 'OAuth2\Storage\ClientInterface',
- 'refresh_token' => 'OAuth2\Storage\RefreshTokenInterface',
- 'user_credentials' => 'OAuth2\Storage\UserCredentialsInterface',
- 'user_claims' => 'OAuth2\OpenID\Storage\UserClaimsInterface',
- 'public_key' => 'OAuth2\Storage\PublicKeyInterface',
- 'jwt_bearer' => 'OAuth2\Storage\JWTBearerInterface',
- 'scope' => 'OAuth2\Storage\ScopeInterface',
- );
-
- protected $responseTypeMap = array(
- 'token' => 'OAuth2\ResponseType\AccessTokenInterface',
- 'code' => 'OAuth2\ResponseType\AuthorizationCodeInterface',
- 'id_token' => 'OAuth2\OpenID\ResponseType\IdTokenInterface',
- 'id_token token' => 'OAuth2\OpenID\ResponseType\IdTokenTokenInterface',
- 'code id_token' => 'OAuth2\OpenID\ResponseType\CodeIdTokenInterface',
- );
-
- /**
- * @param mixed $storage (array or OAuth2\Storage) - single object or array of objects implementing the
- * required storage types (ClientCredentialsInterface and AccessTokenInterface as a minimum)
- * @param array $config specify a different token lifetime, token header name, etc
- * @param array $grantTypes An array of OAuth2\GrantType\GrantTypeInterface to use for granting access tokens
- * @param array $responseTypes Response types to use. array keys should be "code" and and "token" for
- * Access Token and Authorization Code response types
- * @param OAuth2\TokenType\TokenTypeInterface $tokenType The token type object to use. Valid token types are "bearer" and "mac"
- * @param OAuth2\ScopeInterface $scopeUtil The scope utility class to use to validate scope
- * @param OAuth2\ClientAssertionType\ClientAssertionTypeInterface $clientAssertionType The method in which to verify the client identity. Default is HttpBasic
- *
- * @ingroup oauth2_section_7
- */
- public function __construct($storage = array(), array $config = array(), array $grantTypes = array(), array $responseTypes = array(), TokenTypeInterface $tokenType = null, ScopeInterface $scopeUtil = null, ClientAssertionTypeInterface $clientAssertionType = null)
- {
- $storage = is_array($storage) ? $storage : array($storage);
- $this->storages = array();
- foreach ($storage as $key => $service) {
- $this->addStorage($service, $key);
- }
-
- // merge all config values. These get passed to our controller objects
- $this->config = array_merge(array(
- 'use_jwt_access_tokens' => false,
- 'store_encrypted_token_string' => true,
- 'use_openid_connect' => false,
- 'id_lifetime' => 3600,
- 'access_lifetime' => 3600,
- 'www_realm' => 'Service',
- 'token_param_name' => 'access_token',
- 'token_bearer_header_name' => 'Bearer',
- 'enforce_state' => true,
- 'require_exact_redirect_uri' => true,
- 'allow_implicit' => false,
- 'allow_credentials_in_request_body' => true,
- 'allow_public_clients' => true,
- 'always_issue_new_refresh_token' => false,
- 'unset_refresh_token_after_use' => true,
- ), $config);
-
- foreach ($grantTypes as $key => $grantType) {
- $this->addGrantType($grantType, $key);
- }
-
- foreach ($responseTypes as $key => $responseType) {
- $this->addResponseType($responseType, $key);
- }
-
- $this->tokenType = $tokenType;
- $this->scopeUtil = $scopeUtil;
- $this->clientAssertionType = $clientAssertionType;
-
- if ($this->config['use_openid_connect']) {
- $this->validateOpenIdConnect();
- }
- }
-
- public function getAuthorizeController()
- {
- if (is_null($this->authorizeController)) {
- $this->authorizeController = $this->createDefaultAuthorizeController();
- }
-
- return $this->authorizeController;
- }
-
- public function getTokenController()
- {
- if (is_null($this->tokenController)) {
- $this->tokenController = $this->createDefaultTokenController();
- }
-
- return $this->tokenController;
- }
-
- public function getResourceController()
- {
- if (is_null($this->resourceController)) {
- $this->resourceController = $this->createDefaultResourceController();
- }
-
- return $this->resourceController;
- }
-
- public function getUserInfoController()
- {
- if (is_null($this->userInfoController)) {
- $this->userInfoController = $this->createDefaultUserInfoController();
- }
-
- return $this->userInfoController;
- }
-
- /**
- * every getter deserves a setter
- */
- public function setAuthorizeController(AuthorizeControllerInterface $authorizeController)
- {
- $this->authorizeController = $authorizeController;
- }
-
- /**
- * every getter deserves a setter
- */
- public function setTokenController(TokenControllerInterface $tokenController)
- {
- $this->tokenController = $tokenController;
- }
-
- /**
- * every getter deserves a setter
- */
- public function setResourceController(ResourceControllerInterface $resourceController)
- {
- $this->resourceController = $resourceController;
- }
-
- /**
- * every getter deserves a setter
- */
- public function setUserInfoController(UserInfoControllerInterface $userInfoController)
- {
- $this->userInfoController = $userInfoController;
- }
-
- /**
- * Return claims about the authenticated end-user.
- * This would be called from the "/UserInfo" endpoint as defined in the spec.
- *
- * @param $request - OAuth2\RequestInterface
- * Request object to grant access token
- *
- * @param $response - OAuth2\ResponseInterface
- * Response object containing error messages (failure) or user claims (success)
- *
- * @throws InvalidArgumentException
- * @throws LogicException
- *
- * @see http://openid.net/specs/openid-connect-core-1_0.html#UserInfo
- */
- public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response = null)
- {
- $this->response = is_null($response) ? new Response() : $response;
- $this->getUserInfoController()->handleUserInfoRequest($request, $this->response);
-
- return $this->response;
- }
-
- /**
- * Grant or deny a requested access token.
- * This would be called from the "/token" endpoint as defined in the spec.
- * Obviously, you can call your endpoint whatever you want.
- *
- * @param $request - OAuth2\RequestInterface
- * Request object to grant access token
- *
- * @param $response - OAuth2\ResponseInterface
- * Response object containing error messages (failure) or access token (success)
- *
- * @throws InvalidArgumentException
- * @throws LogicException
- *
- * @see http://tools.ietf.org/html/rfc6749#section-4
- * @see http://tools.ietf.org/html/rfc6749#section-10.6
- * @see http://tools.ietf.org/html/rfc6749#section-4.1.3
- *
- * @ingroup oauth2_section_4
- */
- public function handleTokenRequest(RequestInterface $request, ResponseInterface $response = null)
- {
- $this->response = is_null($response) ? new Response() : $response;
- $this->getTokenController()->handleTokenRequest($request, $this->response);
-
- return $this->response;
- }
-
- public function grantAccessToken(RequestInterface $request, ResponseInterface $response = null)
- {
- $this->response = is_null($response) ? new Response() : $response;
- $value = $this->getTokenController()->grantAccessToken($request, $this->response);
-
- return $value;
- }
-
- /**
- * Handle a revoke token request
- * This would be called from the "/revoke" endpoint as defined in the draft Token Revocation spec
- *
- * @see https://tools.ietf.org/html/rfc7009#section-2
- *
- * @param RequestInterface $request
- * @param ResponseInterface $response
- * @return Response|ResponseInterface
- */
- public function handleRevokeRequest(RequestInterface $request, ResponseInterface $response = null)
- {
- $this->response = is_null($response) ? new Response() : $response;
- $this->getTokenController()->handleRevokeRequest($request, $this->response);
-
- return $this->response;
- }
-
- /**
- * Redirect the user appropriately after approval.
- *
- * After the user has approved or denied the resource request the
- * authorization server should call this function to redirect the user
- * appropriately.
- *
- * @param $request
- * The request should have the follow parameters set in the querystring:
- * - response_type: The requested response: an access token, an
- * authorization code, or both.
- * - client_id: The client identifier as described in Section 2.
- * - redirect_uri: An absolute URI to which the authorization server
- * will redirect the user-agent to when the end-user authorization
- * step is completed.
- * - scope: (optional) The scope of the resource request expressed as a
- * list of space-delimited strings.
- * - state: (optional) An opaque value used by the client to maintain
- * state between the request and callback.
- * @param $is_authorized
- * TRUE or FALSE depending on whether the user authorized the access.
- * @param $user_id
- * Identifier of user who authorized the client
- *
- * @see http://tools.ietf.org/html/rfc6749#section-4
- *
- * @ingroup oauth2_section_4
- */
- public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null)
- {
- $this->response = $response;
- $this->getAuthorizeController()->handleAuthorizeRequest($request, $this->response, $is_authorized, $user_id);
-
- return $this->response;
- }
-
- /**
- * Pull the authorization request data out of the HTTP request.
- * - The redirect_uri is OPTIONAL as per draft 20. But your implementation can enforce it
- * by setting $config['enforce_redirect'] to true.
- * - The state is OPTIONAL but recommended to enforce CSRF. Draft 21 states, however, that
- * CSRF protection is MANDATORY. You can enforce this by setting the $config['enforce_state'] to true.
- *
- * The draft specifies that the parameters should be retrieved from GET, override the Response
- * object to change this
- *
- * @return
- * The authorization parameters so the authorization server can prompt
- * the user for approval if valid.
- *
- * @see http://tools.ietf.org/html/rfc6749#section-4.1.1
- * @see http://tools.ietf.org/html/rfc6749#section-10.12
- *
- * @ingroup oauth2_section_3
- */
- public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response = null)
- {
- $this->response = is_null($response) ? new Response() : $response;
- $value = $this->getAuthorizeController()->validateAuthorizeRequest($request, $this->response);
-
- return $value;
- }
-
- public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response = null, $scope = null)
- {
- $this->response = is_null($response) ? new Response() : $response;
- $value = $this->getResourceController()->verifyResourceRequest($request, $this->response, $scope);
-
- return $value;
- }
-
- public function getAccessTokenData(RequestInterface $request, ResponseInterface $response = null)
- {
- $this->response = is_null($response) ? new Response() : $response;
- $value = $this->getResourceController()->getAccessTokenData($request, $this->response);
-
- return $value;
- }
-
- public function addGrantType(GrantTypeInterface $grantType, $identifier = null)
- {
- if (!is_string($identifier)) {
- $identifier = $grantType->getQuerystringIdentifier();
- }
-
- $this->grantTypes[$identifier] = $grantType;
-
- // persist added grant type down to TokenController
- if (!is_null($this->tokenController)) {
- $this->getTokenController()->addGrantType($grantType, $identifier);
- }
- }
-
- /**
- * Set a storage object for the server
- *
- * @param $storage
- * An object implementing one of the Storage interfaces
- * @param $key
- * If null, the storage is set to the key of each storage interface it implements
- *
- * @see storageMap
- */
- public function addStorage($storage, $key = null)
- {
- // if explicitly set to a valid key, do not "magically" set below
- if (isset($this->storageMap[$key])) {
- if (!is_null($storage) && !$storage instanceof $this->storageMap[$key]) {
- throw new \InvalidArgumentException(sprintf('storage of type "%s" must implement interface "%s"', $key, $this->storageMap[$key]));
- }
- $this->storages[$key] = $storage;
-
- // special logic to handle "client" and "client_credentials" strangeness
- if ($key === 'client' && !isset($this->storages['client_credentials'])) {
- if ($storage instanceof \OAuth2\Storage\ClientCredentialsInterface) {
- $this->storages['client_credentials'] = $storage;
- }
- } elseif ($key === 'client_credentials' && !isset($this->storages['client'])) {
- if ($storage instanceof \OAuth2\Storage\ClientInterface) {
- $this->storages['client'] = $storage;
- }
- }
- } elseif (!is_null($key) && !is_numeric($key)) {
- throw new \InvalidArgumentException(sprintf('unknown storage key "%s", must be one of [%s]', $key, implode(', ', array_keys($this->storageMap))));
- } else {
- $set = false;
- foreach ($this->storageMap as $type => $interface) {
- if ($storage instanceof $interface) {
- $this->storages[$type] = $storage;
- $set = true;
- }
- }
-
- if (!$set) {
- throw new \InvalidArgumentException(sprintf('storage of class "%s" must implement one of [%s]', get_class($storage), implode(', ', $this->storageMap)));
- }
- }
- }
-
- public function addResponseType(ResponseTypeInterface $responseType, $key = null)
- {
- $key = $this->normalizeResponseType($key);
-
- if (isset($this->responseTypeMap[$key])) {
- if (!$responseType instanceof $this->responseTypeMap[$key]) {
- throw new \InvalidArgumentException(sprintf('responseType of type "%s" must implement interface "%s"', $key, $this->responseTypeMap[$key]));
- }
- $this->responseTypes[$key] = $responseType;
- } elseif (!is_null($key) && !is_numeric($key)) {
- throw new \InvalidArgumentException(sprintf('unknown responseType key "%s", must be one of [%s]', $key, implode(', ', array_keys($this->responseTypeMap))));
- } else {
- $set = false;
- foreach ($this->responseTypeMap as $type => $interface) {
- if ($responseType instanceof $interface) {
- $this->responseTypes[$type] = $responseType;
- $set = true;
- }
- }
-
- if (!$set) {
- throw new \InvalidArgumentException(sprintf('Unknown response type %s. Please implement one of [%s]', get_class($responseType), implode(', ', $this->responseTypeMap)));
- }
- }
- }
-
- public function getScopeUtil()
- {
- if (!$this->scopeUtil) {
- $storage = isset($this->storages['scope']) ? $this->storages['scope'] : null;
- $this->scopeUtil = new Scope($storage);
- }
-
- return $this->scopeUtil;
- }
-
- /**
- * every getter deserves a setter
- */
- public function setScopeUtil($scopeUtil)
- {
- $this->scopeUtil = $scopeUtil;
- }
-
- protected function createDefaultAuthorizeController()
- {
- if (!isset($this->storages['client'])) {
- throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\ClientInterface to use the authorize server");
- }
- if (0 == count($this->responseTypes)) {
- $this->responseTypes = $this->getDefaultResponseTypes();
- }
- if ($this->config['use_openid_connect'] && !isset($this->responseTypes['id_token'])) {
- $this->responseTypes['id_token'] = $this->createDefaultIdTokenResponseType();
- if ($this->config['allow_implicit']) {
- $this->responseTypes['id_token token'] = $this->createDefaultIdTokenTokenResponseType();
- }
- }
-
- $config = array_intersect_key($this->config, array_flip(explode(' ', 'allow_implicit enforce_state require_exact_redirect_uri')));
-
- if ($this->config['use_openid_connect']) {
- return new OpenIDAuthorizeController($this->storages['client'], $this->responseTypes, $config, $this->getScopeUtil());
- }
-
- return new AuthorizeController($this->storages['client'], $this->responseTypes, $config, $this->getScopeUtil());
- }
-
- protected function createDefaultTokenController()
- {
- if (0 == count($this->grantTypes)) {
- $this->grantTypes = $this->getDefaultGrantTypes();
- }
-
- if (is_null($this->clientAssertionType)) {
- // see if HttpBasic assertion type is requred. If so, then create it from storage classes.
- foreach ($this->grantTypes as $grantType) {
- if (!$grantType instanceof ClientAssertionTypeInterface) {
- if (!isset($this->storages['client_credentials'])) {
- throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\ClientCredentialsInterface to use the token server");
- }
- $config = array_intersect_key($this->config, array_flip(explode(' ', 'allow_credentials_in_request_body allow_public_clients')));
- $this->clientAssertionType = new HttpBasic($this->storages['client_credentials'], $config);
- break;
- }
- }
- }
-
- if (!isset($this->storages['client'])) {
- throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\ClientInterface to use the token server");
- }
-
- $accessTokenResponseType = $this->getAccessTokenResponseType();
-
- return new TokenController($accessTokenResponseType, $this->storages['client'], $this->grantTypes, $this->clientAssertionType, $this->getScopeUtil());
- }
-
- protected function createDefaultResourceController()
- {
- if ($this->config['use_jwt_access_tokens']) {
- // overwrites access token storage with crypto token storage if "use_jwt_access_tokens" is set
- if (!isset($this->storages['access_token']) || !$this->storages['access_token'] instanceof JwtAccessTokenInterface) {
- $this->storages['access_token'] = $this->createDefaultJwtAccessTokenStorage();
- }
- } elseif (!isset($this->storages['access_token'])) {
- throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\AccessTokenInterface or use JwtAccessTokens to use the resource server");
- }
-
- if (!$this->tokenType) {
- $this->tokenType = $this->getDefaultTokenType();
- }
-
- $config = array_intersect_key($this->config, array('www_realm' => ''));
-
- return new ResourceController($this->tokenType, $this->storages['access_token'], $config, $this->getScopeUtil());
- }
-
- protected function createDefaultUserInfoController()
- {
- if ($this->config['use_jwt_access_tokens']) {
- // overwrites access token storage with crypto token storage if "use_jwt_access_tokens" is set
- if (!isset($this->storages['access_token']) || !$this->storages['access_token'] instanceof JwtAccessTokenInterface) {
- $this->storages['access_token'] = $this->createDefaultJwtAccessTokenStorage();
- }
- } elseif (!isset($this->storages['access_token'])) {
- throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\AccessTokenInterface or use JwtAccessTokens to use the UserInfo server");
- }
-
- if (!isset($this->storages['user_claims'])) {
- throw new \LogicException("You must supply a storage object implementing OAuth2\OpenID\Storage\UserClaimsInterface to use the UserInfo server");
- }
-
- if (!$this->tokenType) {
- $this->tokenType = $this->getDefaultTokenType();
- }
-
- $config = array_intersect_key($this->config, array('www_realm' => ''));
-
- return new UserInfoController($this->tokenType, $this->storages['access_token'], $this->storages['user_claims'], $config, $this->getScopeUtil());
- }
-
- protected function getDefaultTokenType()
- {
- $config = array_intersect_key($this->config, array_flip(explode(' ', 'token_param_name token_bearer_header_name')));
-
- return new Bearer($config);
- }
-
- protected function getDefaultResponseTypes()
- {
- $responseTypes = array();
-
- if ($this->config['allow_implicit']) {
- $responseTypes['token'] = $this->getAccessTokenResponseType();
- }
-
- if ($this->config['use_openid_connect']) {
- $responseTypes['id_token'] = $this->getIdTokenResponseType();
- if ($this->config['allow_implicit']) {
- $responseTypes['id_token token'] = $this->getIdTokenTokenResponseType();
- }
- }
-
- if (isset($this->storages['authorization_code'])) {
- $config = array_intersect_key($this->config, array_flip(explode(' ', 'enforce_redirect auth_code_lifetime')));
- if ($this->config['use_openid_connect']) {
- if (!$this->storages['authorization_code'] instanceof OpenIDAuthorizationCodeInterface) {
- throw new \LogicException("Your authorization_code storage must implement OAuth2\OpenID\Storage\AuthorizationCodeInterface to work when 'use_openid_connect' is true");
- }
- $responseTypes['code'] = new OpenIDAuthorizationCodeResponseType($this->storages['authorization_code'], $config);
- $responseTypes['code id_token'] = new CodeIdToken($responseTypes['code'], $responseTypes['id_token']);
- } else {
- $responseTypes['code'] = new AuthorizationCodeResponseType($this->storages['authorization_code'], $config);
- }
- }
-
- if (count($responseTypes) == 0) {
- throw new \LogicException("You must supply an array of response_types in the constructor or implement a OAuth2\Storage\AuthorizationCodeInterface storage object or set 'allow_implicit' to true and implement a OAuth2\Storage\AccessTokenInterface storage object");
- }
-
- return $responseTypes;
- }
-
- protected function getDefaultGrantTypes()
- {
- $grantTypes = array();
-
- if (isset($this->storages['user_credentials'])) {
- $grantTypes['password'] = new UserCredentials($this->storages['user_credentials']);
- }
-
- if (isset($this->storages['client_credentials'])) {
- $config = array_intersect_key($this->config, array('allow_credentials_in_request_body' => ''));
- $grantTypes['client_credentials'] = new ClientCredentials($this->storages['client_credentials'], $config);
- }
-
- if (isset($this->storages['refresh_token'])) {
- $config = array_intersect_key($this->config, array_flip(explode(' ', 'always_issue_new_refresh_token unset_refresh_token_after_use')));
- $grantTypes['refresh_token'] = new RefreshToken($this->storages['refresh_token'], $config);
- }
-
- if (isset($this->storages['authorization_code'])) {
- if ($this->config['use_openid_connect']) {
- if (!$this->storages['authorization_code'] instanceof OpenIDAuthorizationCodeInterface) {
- throw new \LogicException("Your authorization_code storage must implement OAuth2\OpenID\Storage\AuthorizationCodeInterface to work when 'use_openid_connect' is true");
- }
- $grantTypes['authorization_code'] = new OpenIDAuthorizationCodeGrantType($this->storages['authorization_code']);
- } else {
- $grantTypes['authorization_code'] = new AuthorizationCode($this->storages['authorization_code']);
- }
- }
-
- if (count($grantTypes) == 0) {
- throw new \LogicException("Unable to build default grant types - You must supply an array of grant_types in the constructor");
- }
-
- return $grantTypes;
- }
-
- protected function getAccessTokenResponseType()
- {
- if (isset($this->responseTypes['token'])) {
- return $this->responseTypes['token'];
- }
-
- if ($this->config['use_jwt_access_tokens']) {
- return $this->createDefaultJwtAccessTokenResponseType();
- }
-
- return $this->createDefaultAccessTokenResponseType();
- }
-
- protected function getIdTokenResponseType()
- {
- if (isset($this->responseTypes['id_token'])) {
- return $this->responseTypes['id_token'];
- }
-
- return $this->createDefaultIdTokenResponseType();
- }
-
- protected function getIdTokenTokenResponseType()
- {
- if (isset($this->responseTypes['id_token token'])) {
- return $this->responseTypes['id_token token'];
- }
-
- return $this->createDefaultIdTokenTokenResponseType();
- }
-
- /**
- * For Resource Controller
- */
- protected function createDefaultJwtAccessTokenStorage()
- {
- if (!isset($this->storages['public_key'])) {
- throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use crypto tokens");
- }
- $tokenStorage = null;
- if (!empty($this->config['store_encrypted_token_string']) && isset($this->storages['access_token'])) {
- $tokenStorage = $this->storages['access_token'];
- }
- // wrap the access token storage as required.
- return new JwtAccessTokenStorage($this->storages['public_key'], $tokenStorage);
- }
-
- /**
- * For Authorize and Token Controllers
- */
- protected function createDefaultJwtAccessTokenResponseType()
- {
- if (!isset($this->storages['public_key'])) {
- throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use crypto tokens");
- }
-
- $tokenStorage = null;
- if (isset($this->storages['access_token'])) {
- $tokenStorage = $this->storages['access_token'];
- }
-
- $refreshStorage = null;
- if (isset($this->storages['refresh_token'])) {
- $refreshStorage = $this->storages['refresh_token'];
- }
-
- $config = array_intersect_key($this->config, array_flip(explode(' ', 'store_encrypted_token_string issuer access_lifetime refresh_token_lifetime')));
-
- return new JwtAccessToken($this->storages['public_key'], $tokenStorage, $refreshStorage, $config);
- }
-
- protected function createDefaultAccessTokenResponseType()
- {
- if (!isset($this->storages['access_token'])) {
- throw new \LogicException("You must supply a response type implementing OAuth2\ResponseType\AccessTokenInterface, or a storage object implementing OAuth2\Storage\AccessTokenInterface to use the token server");
- }
-
- $refreshStorage = null;
- if (isset($this->storages['refresh_token'])) {
- $refreshStorage = $this->storages['refresh_token'];
- }
-
- $config = array_intersect_key($this->config, array_flip(explode(' ', 'access_lifetime refresh_token_lifetime')));
- $config['token_type'] = $this->tokenType ? $this->tokenType->getTokenType() : $this->getDefaultTokenType()->getTokenType();
-
- return new AccessToken($this->storages['access_token'], $refreshStorage, $config);
- }
-
- protected function createDefaultIdTokenResponseType()
- {
- if (!isset($this->storages['user_claims'])) {
- throw new \LogicException("You must supply a storage object implementing OAuth2\OpenID\Storage\UserClaimsInterface to use openid connect");
- }
- if (!isset($this->storages['public_key'])) {
- throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use openid connect");
- }
-
- $config = array_intersect_key($this->config, array_flip(explode(' ', 'issuer id_lifetime')));
-
- return new IdToken($this->storages['user_claims'], $this->storages['public_key'], $config);
- }
-
- protected function createDefaultIdTokenTokenResponseType()
- {
- return new IdTokenToken($this->getAccessTokenResponseType(), $this->getIdTokenResponseType());
- }
-
- protected function validateOpenIdConnect()
- {
- $authCodeGrant = $this->getGrantType('authorization_code');
- if (!empty($authCodeGrant) && !$authCodeGrant instanceof OpenIDAuthorizationCodeGrantType) {
- throw new \InvalidArgumentException('You have enabled OpenID Connect, but supplied a grant type that does not support it.');
- }
- }
-
- protected function normalizeResponseType($name)
- {
- // for multiple-valued response types - make them alphabetical
- if (!empty($name) && false !== strpos($name, ' ')) {
- $types = explode(' ', $name);
- sort($types);
- $name = implode(' ', $types);
- }
-
- return $name;
- }
-
- public function getResponse()
- {
- return $this->response;
- }
-
- public function getStorages()
- {
- return $this->storages;
- }
-
- public function getStorage($name)
- {
- return isset($this->storages[$name]) ? $this->storages[$name] : null;
- }
-
- public function getGrantTypes()
- {
- return $this->grantTypes;
- }
-
- public function getGrantType($name)
- {
- return isset($this->grantTypes[$name]) ? $this->grantTypes[$name] : null;
- }
-
- public function getResponseTypes()
- {
- return $this->responseTypes;
- }
-
- public function getResponseType($name)
- {
- // for multiple-valued response types - make them alphabetical
- $name = $this->normalizeResponseType($name);
-
- return isset($this->responseTypes[$name]) ? $this->responseTypes[$name] : null;
- }
-
- public function getTokenType()
- {
- return $this->tokenType;
- }
-
- public function getClientAssertionType()
- {
- return $this->clientAssertionType;
- }
-
- public function setConfig($name, $value)
- {
- $this->config[$name] = $value;
- }
-
- public function getConfig($name, $default = null)
- {
- return isset($this->config[$name]) ? $this->config[$name] : $default;
- }
-}
diff --git a/library/oauth2/src/OAuth2/Storage/AccessTokenInterface.php b/library/oauth2/src/OAuth2/Storage/AccessTokenInterface.php
deleted file mode 100644
index 1819158af..000000000
--- a/library/oauth2/src/OAuth2/Storage/AccessTokenInterface.php
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-/**
- * Implement this interface to specify where the OAuth2 Server
- * should get/save access tokens
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-interface AccessTokenInterface
-{
- /**
- * Look up the supplied oauth_token from storage.
- *
- * We need to retrieve access token data as we create and verify tokens.
- *
- * @param $oauth_token
- * oauth_token to be check with.
- *
- * @return
- * An associative array as below, and return NULL if the supplied oauth_token
- * is invalid:
- * - expires: Stored expiration in unix timestamp.
- * - client_id: (optional) Stored client identifier.
- * - user_id: (optional) Stored user identifier.
- * - scope: (optional) Stored scope values in space-separated string.
- * - id_token: (optional) Stored id_token (if "use_openid_connect" is true).
- *
- * @ingroup oauth2_section_7
- */
- public function getAccessToken($oauth_token);
-
- /**
- * Store the supplied access token values to storage.
- *
- * We need to store access token data as we create and verify tokens.
- *
- * @param $oauth_token oauth_token to be stored.
- * @param $client_id client identifier to be stored.
- * @param $user_id user identifier to be stored.
- * @param int $expires expiration to be stored as a Unix timestamp.
- * @param string $scope OPTIONAL Scopes to be stored in space-separated string.
- *
- * @ingroup oauth2_section_4
- */
- public function setAccessToken($oauth_token, $client_id, $user_id, $expires, $scope = null);
-
- /**
- * Expire an access token.
- *
- * This is not explicitly required in the spec, but if defined in a draft RFC for token
- * revoking (RFC 7009) https://tools.ietf.org/html/rfc7009
- *
- * @param $access_token
- * Access token to be expired.
- *
- * @return BOOL true if an access token was unset, false if not
- * @ingroup oauth2_section_6
- *
- * @todo v2.0 include this method in interface. Omitted to maintain BC in v1.x
- */
- //public function unsetAccessToken($access_token);
-}
diff --git a/library/oauth2/src/OAuth2/Storage/AuthorizationCodeInterface.php b/library/oauth2/src/OAuth2/Storage/AuthorizationCodeInterface.php
deleted file mode 100644
index 3beb0e437..000000000
--- a/library/oauth2/src/OAuth2/Storage/AuthorizationCodeInterface.php
+++ /dev/null
@@ -1,86 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-/**
- * Implement this interface to specify where the OAuth2 Server
- * should get/save authorization codes for the "Authorization Code"
- * grant type
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-interface AuthorizationCodeInterface
-{
- /**
- * The Authorization Code grant type supports a response type of "code".
- *
- * @var string
- * @see http://tools.ietf.org/html/rfc6749#section-1.4.1
- * @see http://tools.ietf.org/html/rfc6749#section-4.2
- */
- const RESPONSE_TYPE_CODE = "code";
-
- /**
- * Fetch authorization code data (probably the most common grant type).
- *
- * Retrieve the stored data for the given authorization code.
- *
- * Required for OAuth2::GRANT_TYPE_AUTH_CODE.
- *
- * @param $code
- * Authorization code to be check with.
- *
- * @return
- * An associative array as below, and NULL if the code is invalid
- * @code
- * return array(
- * "client_id" => CLIENT_ID, // REQUIRED Stored client identifier
- * "user_id" => USER_ID, // REQUIRED Stored user identifier
- * "expires" => EXPIRES, // REQUIRED Stored expiration in unix timestamp
- * "redirect_uri" => REDIRECT_URI, // REQUIRED Stored redirect URI
- * "scope" => SCOPE, // OPTIONAL Stored scope values in space-separated string
- * );
- * @endcode
- *
- * @see http://tools.ietf.org/html/rfc6749#section-4.1
- *
- * @ingroup oauth2_section_4
- */
- public function getAuthorizationCode($code);
-
- /**
- * Take the provided authorization code values and store them somewhere.
- *
- * This function should be the storage counterpart to getAuthCode().
- *
- * If storage fails for some reason, we're not currently checking for
- * any sort of success/failure, so you should bail out of the script
- * and provide a descriptive fail message.
- *
- * Required for OAuth2::GRANT_TYPE_AUTH_CODE.
- *
- * @param string $code Authorization code to be stored.
- * @param mixed $client_id Client identifier to be stored.
- * @param mixed $user_id User identifier to be stored.
- * @param string $redirect_uri Redirect URI(s) to be stored in a space-separated string.
- * @param int $expires Expiration to be stored as a Unix timestamp.
- * @param string $scope OPTIONAL Scopes to be stored in space-separated string.
- *
- * @ingroup oauth2_section_4
- */
- public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null);
-
- /**
- * once an Authorization Code is used, it must be exipired
- *
- * @see http://tools.ietf.org/html/rfc6749#section-4.1.2
- *
- * The client MUST NOT use the authorization code
- * more than once. If an authorization code is used more than
- * once, the authorization server MUST deny the request and SHOULD
- * revoke (when possible) all tokens previously issued based on
- * that authorization code
- *
- */
- public function expireAuthorizationCode($code);
-}
diff --git a/library/oauth2/src/OAuth2/Storage/Cassandra.php b/library/oauth2/src/OAuth2/Storage/Cassandra.php
deleted file mode 100644
index 602e8a058..000000000
--- a/library/oauth2/src/OAuth2/Storage/Cassandra.php
+++ /dev/null
@@ -1,480 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-use phpcassa\ColumnFamily;
-use phpcassa\ColumnSlice;
-use phpcassa\Connection\ConnectionPool;
-use OAuth2\OpenID\Storage\UserClaimsInterface;
-use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
-
-/**
- * Cassandra storage for all storage types
- *
- * To use, install "thobbs/phpcassa" via composer
- * <code>
- * composer require thobbs/phpcassa:dev-master
- * </code>
- *
- * Once this is done, instantiate the
- * <code>
- * $cassandra = new \phpcassa\Connection\ConnectionPool('oauth2_server', array('127.0.0.1:9160'));
- * </code>
- *
- * Then, register the storage client:
- * <code>
- * $storage = new OAuth2\Storage\Cassandra($cassandra);
- * $storage->setClientDetails($client_id, $client_secret, $redirect_uri);
- * </code>
- *
- * @see test/lib/OAuth2/Storage/Bootstrap::getCassandraStorage
- */
-class Cassandra implements AuthorizationCodeInterface,
- AccessTokenInterface,
- ClientCredentialsInterface,
- UserCredentialsInterface,
- RefreshTokenInterface,
- JwtBearerInterface,
- ScopeInterface,
- PublicKeyInterface,
- UserClaimsInterface,
- OpenIDAuthorizationCodeInterface
-{
-
- private $cache;
-
- /* The cassandra client */
- protected $cassandra;
-
- /* Configuration array */
- protected $config;
-
- /**
- * Cassandra Storage! uses phpCassa
- *
- * @param \phpcassa\ConnectionPool $cassandra
- * @param array $config
- */
- public function __construct($connection = array(), array $config = array())
- {
- if ($connection instanceof ConnectionPool) {
- $this->cassandra = $connection;
- } else {
- if (!is_array($connection)) {
- throw new \InvalidArgumentException('First argument to OAuth2\Storage\Cassandra must be an instance of phpcassa\Connection\ConnectionPool or a configuration array');
- }
- $connection = array_merge(array(
- 'keyspace' => 'oauth2',
- 'servers' => null,
- ), $connection);
-
- $this->cassandra = new ConnectionPool($connection['keyspace'], $connection['servers']);
- }
-
- $this->config = array_merge(array(
- // cassandra config
- 'column_family' => 'auth',
-
- // key names
- 'client_key' => 'oauth_clients:',
- 'access_token_key' => 'oauth_access_tokens:',
- 'refresh_token_key' => 'oauth_refresh_tokens:',
- 'code_key' => 'oauth_authorization_codes:',
- 'user_key' => 'oauth_users:',
- 'jwt_key' => 'oauth_jwt:',
- 'scope_key' => 'oauth_scopes:',
- 'public_key_key' => 'oauth_public_keys:',
- ), $config);
- }
-
- protected function getValue($key)
- {
- if (isset($this->cache[$key])) {
- return $this->cache[$key];
- }
- $cf = new ColumnFamily($this->cassandra, $this->config['column_family']);
-
- try {
- $value = $cf->get($key, new ColumnSlice("", ""));
- $value = array_shift($value);
- } catch (\cassandra\NotFoundException $e) {
- return false;
- }
-
- return json_decode($value, true);
- }
-
- protected function setValue($key, $value, $expire = 0)
- {
- $this->cache[$key] = $value;
-
- $cf = new ColumnFamily($this->cassandra, $this->config['column_family']);
-
- $str = json_encode($value);
- if ($expire > 0) {
- try {
- $seconds = $expire - time();
- // __data key set as C* requires a field, note: max TTL can only be 630720000 seconds
- $cf->insert($key, array('__data' => $str), null, $seconds);
- } catch (\Exception $e) {
- return false;
- }
- } else {
- try {
- // __data key set as C* requires a field
- $cf->insert($key, array('__data' => $str));
- } catch (\Exception $e) {
- return false;
- }
- }
-
- return true;
- }
-
- protected function expireValue($key)
- {
- unset($this->cache[$key]);
-
- $cf = new ColumnFamily($this->cassandra, $this->config['column_family']);
-
- if ($cf->get_count($key) > 0) {
- try {
- // __data key set as C* requires a field
- $cf->remove($key, array('__data'));
- } catch (\Exception $e) {
- return false;
- }
-
- return true;
- }
-
- return false;
- }
-
- /* AuthorizationCodeInterface */
- public function getAuthorizationCode($code)
- {
- return $this->getValue($this->config['code_key'] . $code);
- }
-
- public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
- {
- return $this->setValue(
- $this->config['code_key'] . $authorization_code,
- compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'),
- $expires
- );
- }
-
- public function expireAuthorizationCode($code)
- {
- $key = $this->config['code_key'] . $code;
- unset($this->cache[$key]);
-
- return $this->expireValue($key);
- }
-
- /* UserCredentialsInterface */
- public function checkUserCredentials($username, $password)
- {
- if ($user = $this->getUser($username)) {
- return $this->checkPassword($user, $password);
- }
-
- return false;
- }
-
- // plaintext passwords are bad! Override this for your application
- protected function checkPassword($user, $password)
- {
- return $user['password'] == $this->hashPassword($password);
- }
-
- // use a secure hashing algorithm when storing passwords. Override this for your application
- protected function hashPassword($password)
- {
- return sha1($password);
- }
-
- public function getUserDetails($username)
- {
- return $this->getUser($username);
- }
-
- public function getUser($username)
- {
- if (!$userInfo = $this->getValue($this->config['user_key'] . $username)) {
- return false;
- }
-
- // the default behavior is to use "username" as the user_id
- return array_merge(array(
- 'user_id' => $username,
- ), $userInfo);
- }
-
- public function setUser($username, $password, $first_name = null, $last_name = null)
- {
- $password = $this->hashPassword($password);
-
- return $this->setValue(
- $this->config['user_key'] . $username,
- compact('username', 'password', 'first_name', 'last_name')
- );
- }
-
- /* ClientCredentialsInterface */
- public function checkClientCredentials($client_id, $client_secret = null)
- {
- if (!$client = $this->getClientDetails($client_id)) {
- return false;
- }
-
- return isset($client['client_secret'])
- && $client['client_secret'] == $client_secret;
- }
-
- public function isPublicClient($client_id)
- {
- if (!$client = $this->getClientDetails($client_id)) {
- return false;
- }
-
- return empty($client['client_secret']);;
- }
-
- /* ClientInterface */
- public function getClientDetails($client_id)
- {
- return $this->getValue($this->config['client_key'] . $client_id);
- }
-
- public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
- {
- return $this->setValue(
- $this->config['client_key'] . $client_id,
- compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id')
- );
- }
-
- public function checkRestrictedGrantType($client_id, $grant_type)
- {
- $details = $this->getClientDetails($client_id);
- if (isset($details['grant_types'])) {
- $grant_types = explode(' ', $details['grant_types']);
-
- return in_array($grant_type, (array) $grant_types);
- }
-
- // if grant_types are not defined, then none are restricted
- return true;
- }
-
- /* RefreshTokenInterface */
- public function getRefreshToken($refresh_token)
- {
- return $this->getValue($this->config['refresh_token_key'] . $refresh_token);
- }
-
- public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
- {
- return $this->setValue(
- $this->config['refresh_token_key'] . $refresh_token,
- compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope'),
- $expires
- );
- }
-
- public function unsetRefreshToken($refresh_token)
- {
- return $this->expireValue($this->config['refresh_token_key'] . $refresh_token);
- }
-
- /* AccessTokenInterface */
- public function getAccessToken($access_token)
- {
- return $this->getValue($this->config['access_token_key'].$access_token);
- }
-
- public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
- {
- return $this->setValue(
- $this->config['access_token_key'].$access_token,
- compact('access_token', 'client_id', 'user_id', 'expires', 'scope'),
- $expires
- );
- }
-
- public function unsetAccessToken($access_token)
- {
- return $this->expireValue($this->config['access_token_key'] . $access_token);
- }
-
- /* ScopeInterface */
- public function scopeExists($scope)
- {
- $scope = explode(' ', $scope);
-
- $result = $this->getValue($this->config['scope_key'].'supported:global');
-
- $supportedScope = explode(' ', (string) $result);
-
- return (count(array_diff($scope, $supportedScope)) == 0);
- }
-
- public function getDefaultScope($client_id = null)
- {
- if (is_null($client_id) || !$result = $this->getValue($this->config['scope_key'].'default:'.$client_id)) {
- $result = $this->getValue($this->config['scope_key'].'default:global');
- }
-
- return $result;
- }
-
- public function setScope($scope, $client_id = null, $type = 'supported')
- {
- if (!in_array($type, array('default', 'supported'))) {
- throw new \InvalidArgumentException('"$type" must be one of "default", "supported"');
- }
-
- if (is_null($client_id)) {
- $key = $this->config['scope_key'].$type.':global';
- } else {
- $key = $this->config['scope_key'].$type.':'.$client_id;
- }
-
- return $this->setValue($key, $scope);
- }
-
- /*JWTBearerInterface */
- public function getClientKey($client_id, $subject)
- {
- if (!$jwt = $this->getValue($this->config['jwt_key'] . $client_id)) {
- return false;
- }
-
- if (isset($jwt['subject']) && $jwt['subject'] == $subject ) {
- return $jwt['key'];
- }
-
- return null;
- }
-
- public function setClientKey($client_id, $key, $subject = null)
- {
- return $this->setValue($this->config['jwt_key'] . $client_id, array(
- 'key' => $key,
- 'subject' => $subject
- ));
- }
-
- /*ScopeInterface */
- public function getClientScope($client_id)
- {
- if (!$clientDetails = $this->getClientDetails($client_id)) {
- return false;
- }
-
- if (isset($clientDetails['scope'])) {
- return $clientDetails['scope'];
- }
-
- return null;
- }
-
- public function getJti($client_id, $subject, $audience, $expiration, $jti)
- {
- //TODO: Needs cassandra implementation.
- throw new \Exception('getJti() for the Cassandra driver is currently unimplemented.');
- }
-
- public function setJti($client_id, $subject, $audience, $expiration, $jti)
- {
- //TODO: Needs cassandra implementation.
- throw new \Exception('setJti() for the Cassandra driver is currently unimplemented.');
- }
-
- /* PublicKeyInterface */
- public function getPublicKey($client_id = '')
- {
- $public_key = $this->getValue($this->config['public_key_key'] . $client_id);
- if (is_array($public_key)) {
- return $public_key['public_key'];
- }
- $public_key = $this->getValue($this->config['public_key_key']);
- if (is_array($public_key)) {
- return $public_key['public_key'];
- }
- }
-
- public function getPrivateKey($client_id = '')
- {
- $public_key = $this->getValue($this->config['public_key_key'] . $client_id);
- if (is_array($public_key)) {
- return $public_key['private_key'];
- }
- $public_key = $this->getValue($this->config['public_key_key']);
- if (is_array($public_key)) {
- return $public_key['private_key'];
- }
- }
-
- public function getEncryptionAlgorithm($client_id = null)
- {
- $public_key = $this->getValue($this->config['public_key_key'] . $client_id);
- if (is_array($public_key)) {
- return $public_key['encryption_algorithm'];
- }
- $public_key = $this->getValue($this->config['public_key_key']);
- if (is_array($public_key)) {
- return $public_key['encryption_algorithm'];
- }
-
- return 'RS256';
- }
-
- /* UserClaimsInterface */
- public function getUserClaims($user_id, $claims)
- {
- $userDetails = $this->getUserDetails($user_id);
- if (!is_array($userDetails)) {
- return false;
- }
-
- $claims = explode(' ', trim($claims));
- $userClaims = array();
-
- // for each requested claim, if the user has the claim, set it in the response
- $validClaims = explode(' ', self::VALID_CLAIMS);
- foreach ($validClaims as $validClaim) {
- if (in_array($validClaim, $claims)) {
- if ($validClaim == 'address') {
- // address is an object with subfields
- $userClaims['address'] = $this->getUserClaim($validClaim, $userDetails['address'] ?: $userDetails);
- } else {
- $userClaims = array_merge($userClaims, $this->getUserClaim($validClaim, $userDetails));
- }
- }
- }
-
- return $userClaims;
- }
-
- protected function getUserClaim($claim, $userDetails)
- {
- $userClaims = array();
- $claimValuesString = constant(sprintf('self::%s_CLAIM_VALUES', strtoupper($claim)));
- $claimValues = explode(' ', $claimValuesString);
-
- foreach ($claimValues as $value) {
- if ($value == 'email_verified') {
- $userClaims[$value] = $userDetails[$value]=='true' ? true : false;
- } else {
- $userClaims[$value] = isset($userDetails[$value]) ? $userDetails[$value] : null;
- }
- }
-
- return $userClaims;
- }
-
-}
diff --git a/library/oauth2/src/OAuth2/Storage/ClientCredentialsInterface.php b/library/oauth2/src/OAuth2/Storage/ClientCredentialsInterface.php
deleted file mode 100644
index 3318c6966..000000000
--- a/library/oauth2/src/OAuth2/Storage/ClientCredentialsInterface.php
+++ /dev/null
@@ -1,49 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-/**
- * Implement this interface to specify how the OAuth2 Server
- * should verify client credentials
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-interface ClientCredentialsInterface extends ClientInterface
-{
-
- /**
- * Make sure that the client credentials is valid.
- *
- * @param $client_id
- * Client identifier to be check with.
- * @param $client_secret
- * (optional) If a secret is required, check that they've given the right one.
- *
- * @return
- * TRUE if the client credentials are valid, and MUST return FALSE if it isn't.
- * @endcode
- *
- * @see http://tools.ietf.org/html/rfc6749#section-3.1
- *
- * @ingroup oauth2_section_3
- */
- public function checkClientCredentials($client_id, $client_secret = null);
-
- /**
- * Determine if the client is a "public" client, and therefore
- * does not require passing credentials for certain grant types
- *
- * @param $client_id
- * Client identifier to be check with.
- *
- * @return
- * TRUE if the client is public, and FALSE if it isn't.
- * @endcode
- *
- * @see http://tools.ietf.org/html/rfc6749#section-2.3
- * @see https://github.com/bshaffer/oauth2-server-php/issues/257
- *
- * @ingroup oauth2_section_2
- */
- public function isPublicClient($client_id);
-}
diff --git a/library/oauth2/src/OAuth2/Storage/ClientInterface.php b/library/oauth2/src/OAuth2/Storage/ClientInterface.php
deleted file mode 100644
index 09a5bffc1..000000000
--- a/library/oauth2/src/OAuth2/Storage/ClientInterface.php
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-/**
- * Implement this interface to specify where the OAuth2 Server
- * should retrieve client information
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-interface ClientInterface
-{
- /**
- * Get client details corresponding client_id.
- *
- * OAuth says we should store request URIs for each registered client.
- * Implement this function to grab the stored URI for a given client id.
- *
- * @param $client_id
- * Client identifier to be check with.
- *
- * @return array
- * Client details. The only mandatory key in the array is "redirect_uri".
- * This function MUST return FALSE if the given client does not exist or is
- * invalid. "redirect_uri" can be space-delimited to allow for multiple valid uris.
- * <code>
- * return array(
- * "redirect_uri" => REDIRECT_URI, // REQUIRED redirect_uri registered for the client
- * "client_id" => CLIENT_ID, // OPTIONAL the client id
- * "grant_types" => GRANT_TYPES, // OPTIONAL an array of restricted grant types
- * "user_id" => USER_ID, // OPTIONAL the user identifier associated with this client
- * "scope" => SCOPE, // OPTIONAL the scopes allowed for this client
- * );
- * </code>
- *
- * @ingroup oauth2_section_4
- */
- public function getClientDetails($client_id);
-
- /**
- * Get the scope associated with this client
- *
- * @return
- * STRING the space-delineated scope list for the specified client_id
- */
- public function getClientScope($client_id);
-
- /**
- * Check restricted grant types of corresponding client identifier.
- *
- * If you want to restrict clients to certain grant types, override this
- * function.
- *
- * @param $client_id
- * Client identifier to be check with.
- * @param $grant_type
- * Grant type to be check with
- *
- * @return
- * TRUE if the grant type is supported by this client identifier, and
- * FALSE if it isn't.
- *
- * @ingroup oauth2_section_4
- */
- public function checkRestrictedGrantType($client_id, $grant_type);
-}
diff --git a/library/oauth2/src/OAuth2/Storage/CouchbaseDB.php b/library/oauth2/src/OAuth2/Storage/CouchbaseDB.php
deleted file mode 100755
index 1eb55f027..000000000
--- a/library/oauth2/src/OAuth2/Storage/CouchbaseDB.php
+++ /dev/null
@@ -1,331 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
-
-/**
- * Simple Couchbase storage for all storage types
- *
- * This class should be extended or overridden as required
- *
- * NOTE: Passwords are stored in plaintext, which is never
- * a good idea. Be sure to override this for your application
- *
- * @author Tom Park <tom@raucter.com>
- */
-class CouchbaseDB implements AuthorizationCodeInterface,
- AccessTokenInterface,
- ClientCredentialsInterface,
- UserCredentialsInterface,
- RefreshTokenInterface,
- JwtBearerInterface,
- OpenIDAuthorizationCodeInterface
-{
- protected $db;
- protected $config;
-
- public function __construct($connection, $config = array())
- {
- if ($connection instanceof \Couchbase) {
- $this->db = $connection;
- } else {
- if (!is_array($connection) || !is_array($connection['servers'])) {
- throw new \InvalidArgumentException('First argument to OAuth2\Storage\CouchbaseDB must be an instance of Couchbase or a configuration array containing a server array');
- }
-
- $this->db = new \Couchbase($connection['servers'], (!isset($connection['username'])) ? '' : $connection['username'], (!isset($connection['password'])) ? '' : $connection['password'], $connection['bucket'], false);
- }
-
- $this->config = array_merge(array(
- 'client_table' => 'oauth_clients',
- 'access_token_table' => 'oauth_access_tokens',
- 'refresh_token_table' => 'oauth_refresh_tokens',
- 'code_table' => 'oauth_authorization_codes',
- 'user_table' => 'oauth_users',
- 'jwt_table' => 'oauth_jwt',
- ), $config);
- }
-
- // Helper function to access couchbase item by type:
- protected function getObjectByType($name,$id)
- {
- return json_decode($this->db->get($this->config[$name].'-'.$id),true);
- }
-
- // Helper function to set couchbase item by type:
- protected function setObjectByType($name,$id,$array)
- {
- $array['type'] = $name;
-
- return $this->db->set($this->config[$name].'-'.$id,json_encode($array));
- }
-
- // Helper function to delete couchbase item by type, wait for persist to at least 1 node
- protected function deleteObjectByType($name,$id)
- {
- $this->db->delete($this->config[$name].'-'.$id,"",1);
- }
-
- /* ClientCredentialsInterface */
- public function checkClientCredentials($client_id, $client_secret = null)
- {
- if ($result = $this->getObjectByType('client_table',$client_id)) {
- return $result['client_secret'] == $client_secret;
- }
-
- return false;
- }
-
- public function isPublicClient($client_id)
- {
- if (!$result = $this->getObjectByType('client_table',$client_id)) {
- return false;
- }
-
- return empty($result['client_secret']);
- }
-
- /* ClientInterface */
- public function getClientDetails($client_id)
- {
- $result = $this->getObjectByType('client_table',$client_id);
-
- return is_null($result) ? false : $result;
- }
-
- public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
- {
- if ($this->getClientDetails($client_id)) {
-
- $this->setObjectByType('client_table',$client_id, array(
- 'client_id' => $client_id,
- 'client_secret' => $client_secret,
- 'redirect_uri' => $redirect_uri,
- 'grant_types' => $grant_types,
- 'scope' => $scope,
- 'user_id' => $user_id,
- ));
- } else {
- $this->setObjectByType('client_table',$client_id, array(
- 'client_id' => $client_id,
- 'client_secret' => $client_secret,
- 'redirect_uri' => $redirect_uri,
- 'grant_types' => $grant_types,
- 'scope' => $scope,
- 'user_id' => $user_id,
- ));
- }
-
- return true;
- }
-
- public function checkRestrictedGrantType($client_id, $grant_type)
- {
- $details = $this->getClientDetails($client_id);
- if (isset($details['grant_types'])) {
- $grant_types = explode(' ', $details['grant_types']);
-
- return in_array($grant_type, $grant_types);
- }
-
- // if grant_types are not defined, then none are restricted
- return true;
- }
-
- /* AccessTokenInterface */
- public function getAccessToken($access_token)
- {
- $token = $this->getObjectByType('access_token_table',$access_token);
-
- return is_null($token) ? false : $token;
- }
-
- public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
- {
- // if it exists, update it.
- if ($this->getAccessToken($access_token)) {
- $this->setObjectByType('access_token_table',$access_token, array(
- 'access_token' => $access_token,
- 'client_id' => $client_id,
- 'expires' => $expires,
- 'user_id' => $user_id,
- 'scope' => $scope
- ));
- } else {
- $this->setObjectByType('access_token_table',$access_token, array(
- 'access_token' => $access_token,
- 'client_id' => $client_id,
- 'expires' => $expires,
- 'user_id' => $user_id,
- 'scope' => $scope
- ));
- }
-
- return true;
- }
-
- /* AuthorizationCodeInterface */
- public function getAuthorizationCode($code)
- {
- $code = $this->getObjectByType('code_table',$code);
-
- return is_null($code) ? false : $code;
- }
-
- public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
- {
- // if it exists, update it.
- if ($this->getAuthorizationCode($code)) {
- $this->setObjectByType('code_table',$code, array(
- 'authorization_code' => $code,
- 'client_id' => $client_id,
- 'user_id' => $user_id,
- 'redirect_uri' => $redirect_uri,
- 'expires' => $expires,
- 'scope' => $scope,
- 'id_token' => $id_token,
- ));
- } else {
- $this->setObjectByType('code_table',$code,array(
- 'authorization_code' => $code,
- 'client_id' => $client_id,
- 'user_id' => $user_id,
- 'redirect_uri' => $redirect_uri,
- 'expires' => $expires,
- 'scope' => $scope,
- 'id_token' => $id_token,
- ));
- }
-
- return true;
- }
-
- public function expireAuthorizationCode($code)
- {
- $this->deleteObjectByType('code_table',$code);
-
- return true;
- }
-
- /* UserCredentialsInterface */
- public function checkUserCredentials($username, $password)
- {
- if ($user = $this->getUser($username)) {
- return $this->checkPassword($user, $password);
- }
-
- return false;
- }
-
- public function getUserDetails($username)
- {
- if ($user = $this->getUser($username)) {
- $user['user_id'] = $user['username'];
- }
-
- return $user;
- }
-
- /* RefreshTokenInterface */
- public function getRefreshToken($refresh_token)
- {
- $token = $this->getObjectByType('refresh_token_table',$refresh_token);
-
- return is_null($token) ? false : $token;
- }
-
- public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
- {
- $this->setObjectByType('refresh_token_table',$refresh_token, array(
- 'refresh_token' => $refresh_token,
- 'client_id' => $client_id,
- 'user_id' => $user_id,
- 'expires' => $expires,
- 'scope' => $scope
- ));
-
- return true;
- }
-
- public function unsetRefreshToken($refresh_token)
- {
- $this->deleteObjectByType('refresh_token_table',$refresh_token);
-
- return true;
- }
-
- // plaintext passwords are bad! Override this for your application
- protected function checkPassword($user, $password)
- {
- return $user['password'] == $password;
- }
-
- public function getUser($username)
- {
- $result = $this->getObjectByType('user_table',$username);
-
- return is_null($result) ? false : $result;
- }
-
- public function setUser($username, $password, $firstName = null, $lastName = null)
- {
- if ($this->getUser($username)) {
- $this->setObjectByType('user_table',$username, array(
- 'username' => $username,
- 'password' => $password,
- 'first_name' => $firstName,
- 'last_name' => $lastName
- ));
-
- } else {
- $this->setObjectByType('user_table',$username, array(
- 'username' => $username,
- 'password' => $password,
- 'first_name' => $firstName,
- 'last_name' => $lastName
- ));
-
- }
-
- return true;
- }
-
- public function getClientKey($client_id, $subject)
- {
- if (!$jwt = $this->getObjectByType('jwt_table',$client_id)) {
- return false;
- }
-
- if (isset($jwt['subject']) && $jwt['subject'] == $subject) {
- return $jwt['key'];
- }
-
- return false;
- }
-
- public function getClientScope($client_id)
- {
- if (!$clientDetails = $this->getClientDetails($client_id)) {
- return false;
- }
-
- if (isset($clientDetails['scope'])) {
- return $clientDetails['scope'];
- }
-
- return null;
- }
-
- public function getJti($client_id, $subject, $audience, $expiration, $jti)
- {
- //TODO: Needs couchbase implementation.
- throw new \Exception('getJti() for the Couchbase driver is currently unimplemented.');
- }
-
- public function setJti($client_id, $subject, $audience, $expiration, $jti)
- {
- //TODO: Needs couchbase implementation.
- throw new \Exception('setJti() for the Couchbase driver is currently unimplemented.');
- }
-}
diff --git a/library/oauth2/src/OAuth2/Storage/DynamoDB.php b/library/oauth2/src/OAuth2/Storage/DynamoDB.php
deleted file mode 100644
index 8347ab258..000000000
--- a/library/oauth2/src/OAuth2/Storage/DynamoDB.php
+++ /dev/null
@@ -1,540 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-use Aws\DynamoDb\DynamoDbClient;
-
-use OAuth2\OpenID\Storage\UserClaimsInterface;
-use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
-/**
- * DynamoDB storage for all storage types
- *
- * To use, install "aws/aws-sdk-php" via composer
- * <code>
- * composer require aws/aws-sdk-php:dev-master
- * </code>
- *
- * Once this is done, instantiate the DynamoDB client
- * <code>
- * $storage = new OAuth2\Storage\Dynamodb(array("key" => "YOURKEY", "secret" => "YOURSECRET", "region" => "YOURREGION"));
- * </code>
- *
- * Table :
- * - oauth_access_tokens (primary hash key : access_token)
- * - oauth_authorization_codes (primary hash key : authorization_code)
- * - oauth_clients (primary hash key : client_id)
- * - oauth_jwt (primary hash key : client_id, primary range key : subject)
- * - oauth_public_keys (primary hash key : client_id)
- * - oauth_refresh_tokens (primary hash key : refresh_token)
- * - oauth_scopes (primary hash key : scope, secondary index : is_default-index hash key is_default)
- * - oauth_users (primary hash key : username)
- *
- * @author Frederic AUGUSTE <frederic.auguste at gmail dot com>
- */
-class DynamoDB implements
- AuthorizationCodeInterface,
- AccessTokenInterface,
- ClientCredentialsInterface,
- UserCredentialsInterface,
- RefreshTokenInterface,
- JwtBearerInterface,
- ScopeInterface,
- PublicKeyInterface,
- UserClaimsInterface,
- OpenIDAuthorizationCodeInterface
-{
- protected $client;
- protected $config;
-
- public function __construct($connection, $config = array())
- {
- if (!($connection instanceof DynamoDbClient)) {
- if (!is_array($connection)) {
- throw new \InvalidArgumentException('First argument to OAuth2\Storage\Dynamodb must be an instance a configuration array containt key, secret, region');
- }
- if (!array_key_exists("key",$connection) || !array_key_exists("secret",$connection) || !array_key_exists("region",$connection) ) {
- throw new \InvalidArgumentException('First argument to OAuth2\Storage\Dynamodb must be an instance a configuration array containt key, secret, region');
- }
- $this->client = DynamoDbClient::factory(array(
- 'key' => $connection["key"],
- 'secret' => $connection["secret"],
- 'region' =>$connection["region"]
- ));
- } else {
- $this->client = $connection;
- }
-
- $this->config = array_merge(array(
- 'client_table' => 'oauth_clients',
- 'access_token_table' => 'oauth_access_tokens',
- 'refresh_token_table' => 'oauth_refresh_tokens',
- 'code_table' => 'oauth_authorization_codes',
- 'user_table' => 'oauth_users',
- 'jwt_table' => 'oauth_jwt',
- 'scope_table' => 'oauth_scopes',
- 'public_key_table' => 'oauth_public_keys',
- ), $config);
- }
-
- /* OAuth2\Storage\ClientCredentialsInterface */
- public function checkClientCredentials($client_id, $client_secret = null)
- {
- $result = $this->client->getItem(array(
- "TableName"=> $this->config['client_table'],
- "Key" => array('client_id' => array('S' => $client_id))
- ));
-
- return $result->count()==1 && $result["Item"]["client_secret"]["S"] == $client_secret;
- }
-
- public function isPublicClient($client_id)
- {
- $result = $this->client->getItem(array(
- "TableName"=> $this->config['client_table'],
- "Key" => array('client_id' => array('S' => $client_id))
- ));
-
- if ($result->count()==0) {
- return false ;
- }
-
- return empty($result["Item"]["client_secret"]);
- }
-
- /* OAuth2\Storage\ClientInterface */
- public function getClientDetails($client_id)
- {
- $result = $this->client->getItem(array(
- "TableName"=> $this->config['client_table'],
- "Key" => array('client_id' => array('S' => $client_id))
- ));
- if ($result->count()==0) {
- return false ;
- }
- $result = $this->dynamo2array($result);
- foreach (array('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id') as $key => $val) {
- if (!array_key_exists ($val, $result)) {
- $result[$val] = null;
- }
- }
-
- return $result;
- }
-
- public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
- {
- $clientData = compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id');
- $clientData = array_filter($clientData, 'self::isNotEmpty');
-
- $result = $this->client->putItem(array(
- 'TableName' => $this->config['client_table'],
- 'Item' => $this->client->formatAttributes($clientData)
- ));
-
- return true;
- }
-
- public function checkRestrictedGrantType($client_id, $grant_type)
- {
- $details = $this->getClientDetails($client_id);
- if (isset($details['grant_types'])) {
- $grant_types = explode(' ', $details['grant_types']);
-
- return in_array($grant_type, (array) $grant_types);
- }
-
- // if grant_types are not defined, then none are restricted
- return true;
- }
-
- /* OAuth2\Storage\AccessTokenInterface */
- public function getAccessToken($access_token)
- {
- $result = $this->client->getItem(array(
- "TableName"=> $this->config['access_token_table'],
- "Key" => array('access_token' => array('S' => $access_token))
- ));
- if ($result->count()==0) {
- return false ;
- }
- $token = $this->dynamo2array($result);
- if (array_key_exists ('expires', $token)) {
- $token['expires'] = strtotime($token['expires']);
- }
-
- return $token;
- }
-
- public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
- {
- // convert expires to datestring
- $expires = date('Y-m-d H:i:s', $expires);
-
- $clientData = compact('access_token', 'client_id', 'user_id', 'expires', 'scope');
- $clientData = array_filter($clientData, 'self::isNotEmpty');
-
- $result = $this->client->putItem(array(
- 'TableName' => $this->config['access_token_table'],
- 'Item' => $this->client->formatAttributes($clientData)
- ));
-
- return true;
-
- }
-
- public function unsetAccessToken($access_token)
- {
- $result = $this->client->deleteItem(array(
- 'TableName' => $this->config['access_token_table'],
- 'Key' => $this->client->formatAttributes(array("access_token" => $access_token)),
- 'ReturnValues' => 'ALL_OLD',
- ));
-
- return null !== $result->get('Attributes');
- }
-
- /* OAuth2\Storage\AuthorizationCodeInterface */
- public function getAuthorizationCode($code)
- {
- $result = $this->client->getItem(array(
- "TableName"=> $this->config['code_table'],
- "Key" => array('authorization_code' => array('S' => $code))
- ));
- if ($result->count()==0) {
- return false ;
- }
- $token = $this->dynamo2array($result);
- if (!array_key_exists("id_token", $token )) {
- $token['id_token'] = null;
- }
- $token['expires'] = strtotime($token['expires']);
-
- return $token;
-
- }
-
- public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
- {
- // convert expires to datestring
- $expires = date('Y-m-d H:i:s', $expires);
-
- $clientData = compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'id_token', 'scope');
- $clientData = array_filter($clientData, 'self::isNotEmpty');
-
- $result = $this->client->putItem(array(
- 'TableName' => $this->config['code_table'],
- 'Item' => $this->client->formatAttributes($clientData)
- ));
-
- return true;
- }
-
- public function expireAuthorizationCode($code)
- {
-
- $result = $this->client->deleteItem(array(
- 'TableName' => $this->config['code_table'],
- 'Key' => $this->client->formatAttributes(array("authorization_code" => $code))
- ));
-
- return true;
- }
-
- /* OAuth2\Storage\UserCredentialsInterface */
- public function checkUserCredentials($username, $password)
- {
- if ($user = $this->getUser($username)) {
- return $this->checkPassword($user, $password);
- }
-
- return false;
- }
-
- public function getUserDetails($username)
- {
- return $this->getUser($username);
- }
-
- /* UserClaimsInterface */
- public function getUserClaims($user_id, $claims)
- {
- if (!$userDetails = $this->getUserDetails($user_id)) {
- return false;
- }
-
- $claims = explode(' ', trim($claims));
- $userClaims = array();
-
- // for each requested claim, if the user has the claim, set it in the response
- $validClaims = explode(' ', self::VALID_CLAIMS);
- foreach ($validClaims as $validClaim) {
- if (in_array($validClaim, $claims)) {
- if ($validClaim == 'address') {
- // address is an object with subfields
- $userClaims['address'] = $this->getUserClaim($validClaim, $userDetails['address'] ?: $userDetails);
- } else {
- $userClaims = array_merge($userClaims, $this->getUserClaim($validClaim, $userDetails));
- }
- }
- }
-
- return $userClaims;
- }
-
- protected function getUserClaim($claim, $userDetails)
- {
- $userClaims = array();
- $claimValuesString = constant(sprintf('self::%s_CLAIM_VALUES', strtoupper($claim)));
- $claimValues = explode(' ', $claimValuesString);
-
- foreach ($claimValues as $value) {
- if ($value == 'email_verified') {
- $userClaims[$value] = $userDetails[$value]=='true' ? true : false;
- } else {
- $userClaims[$value] = isset($userDetails[$value]) ? $userDetails[$value] : null;
- }
- }
-
- return $userClaims;
- }
-
- /* OAuth2\Storage\RefreshTokenInterface */
- public function getRefreshToken($refresh_token)
- {
- $result = $this->client->getItem(array(
- "TableName"=> $this->config['refresh_token_table'],
- "Key" => array('refresh_token' => array('S' => $refresh_token))
- ));
- if ($result->count()==0) {
- return false ;
- }
- $token = $this->dynamo2array($result);
- $token['expires'] = strtotime($token['expires']);
-
- return $token;
- }
-
- public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
- {
- // convert expires to datestring
- $expires = date('Y-m-d H:i:s', $expires);
-
- $clientData = compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope');
- $clientData = array_filter($clientData, 'self::isNotEmpty');
-
- $result = $this->client->putItem(array(
- 'TableName' => $this->config['refresh_token_table'],
- 'Item' => $this->client->formatAttributes($clientData)
- ));
-
- return true;
- }
-
- public function unsetRefreshToken($refresh_token)
- {
- $result = $this->client->deleteItem(array(
- 'TableName' => $this->config['refresh_token_table'],
- 'Key' => $this->client->formatAttributes(array("refresh_token" => $refresh_token))
- ));
-
- return true;
- }
-
- // plaintext passwords are bad! Override this for your application
- protected function checkPassword($user, $password)
- {
- return $user['password'] == $this->hashPassword($password);
- }
-
- // use a secure hashing algorithm when storing passwords. Override this for your application
- protected function hashPassword($password)
- {
- return sha1($password);
- }
-
- public function getUser($username)
- {
- $result = $this->client->getItem(array(
- "TableName"=> $this->config['user_table'],
- "Key" => array('username' => array('S' => $username))
- ));
- if ($result->count()==0) {
- return false ;
- }
- $token = $this->dynamo2array($result);
- $token['user_id'] = $username;
-
- return $token;
- }
-
- public function setUser($username, $password, $first_name = null, $last_name = null)
- {
- // do not store in plaintext
- $password = $this->hashPassword($password);
-
- $clientData = compact('username', 'password', 'first_name', 'last_name');
- $clientData = array_filter($clientData, 'self::isNotEmpty');
-
- $result = $this->client->putItem(array(
- 'TableName' => $this->config['user_table'],
- 'Item' => $this->client->formatAttributes($clientData)
- ));
-
- return true;
-
- }
-
- /* ScopeInterface */
- public function scopeExists($scope)
- {
- $scope = explode(' ', $scope);
- $scope_query = array();
- $count = 0;
- foreach ($scope as $key => $val) {
- $result = $this->client->query(array(
- 'TableName' => $this->config['scope_table'],
- 'Select' => 'COUNT',
- 'KeyConditions' => array(
- 'scope' => array(
- 'AttributeValueList' => array(array('S' => $val)),
- 'ComparisonOperator' => 'EQ'
- )
- )
- ));
- $count += $result['Count'];
- }
-
- return $count == count($scope);
- }
-
- public function getDefaultScope($client_id = null)
- {
-
- $result = $this->client->query(array(
- 'TableName' => $this->config['scope_table'],
- 'IndexName' => 'is_default-index',
- 'Select' => 'ALL_ATTRIBUTES',
- 'KeyConditions' => array(
- 'is_default' => array(
- 'AttributeValueList' => array(array('S' => 'true')),
- 'ComparisonOperator' => 'EQ',
- ),
- )
- ));
- $defaultScope = array();
- if ($result->count() > 0) {
- $array = $result->toArray();
- foreach ($array["Items"] as $item) {
- $defaultScope[] = $item['scope']['S'];
- }
-
- return empty($defaultScope) ? null : implode(' ', $defaultScope);
- }
-
- return null;
- }
-
- /* JWTBearerInterface */
- public function getClientKey($client_id, $subject)
- {
- $result = $this->client->getItem(array(
- "TableName"=> $this->config['jwt_table'],
- "Key" => array('client_id' => array('S' => $client_id), 'subject' => array('S' => $subject))
- ));
- if ($result->count()==0) {
- return false ;
- }
- $token = $this->dynamo2array($result);
-
- return $token['public_key'];
- }
-
- public function getClientScope($client_id)
- {
- if (!$clientDetails = $this->getClientDetails($client_id)) {
- return false;
- }
-
- if (isset($clientDetails['scope'])) {
- return $clientDetails['scope'];
- }
-
- return null;
- }
-
- public function getJti($client_id, $subject, $audience, $expires, $jti)
- {
- //TODO not use.
- }
-
- public function setJti($client_id, $subject, $audience, $expires, $jti)
- {
- //TODO not use.
- }
-
- /* PublicKeyInterface */
- public function getPublicKey($client_id = '0')
- {
-
- $result = $this->client->getItem(array(
- "TableName"=> $this->config['public_key_table'],
- "Key" => array('client_id' => array('S' => $client_id))
- ));
- if ($result->count()==0) {
- return false ;
- }
- $token = $this->dynamo2array($result);
-
- return $token['public_key'];
-
- }
-
- public function getPrivateKey($client_id = '0')
- {
- $result = $this->client->getItem(array(
- "TableName"=> $this->config['public_key_table'],
- "Key" => array('client_id' => array('S' => $client_id))
- ));
- if ($result->count()==0) {
- return false ;
- }
- $token = $this->dynamo2array($result);
-
- return $token['private_key'];
- }
-
- public function getEncryptionAlgorithm($client_id = null)
- {
- $result = $this->client->getItem(array(
- "TableName"=> $this->config['public_key_table'],
- "Key" => array('client_id' => array('S' => $client_id))
- ));
- if ($result->count()==0) {
- return 'RS256' ;
- }
- $token = $this->dynamo2array($result);
-
- return $token['encryption_algorithm'];
- }
-
- /**
- * Transform dynamodb resultset to an array.
- * @param $dynamodbResult
- * @return $array
- */
- private function dynamo2array($dynamodbResult)
- {
- $result = array();
- foreach ($dynamodbResult["Item"] as $key => $val) {
- $result[$key] = $val["S"];
- $result[] = $val["S"];
- }
-
- return $result;
- }
-
- private static function isNotEmpty($value)
- {
- return null !== $value && '' !== $value;
- }
-}
diff --git a/library/oauth2/src/OAuth2/Storage/JwtAccessToken.php b/library/oauth2/src/OAuth2/Storage/JwtAccessToken.php
deleted file mode 100644
index 75b49d301..000000000
--- a/library/oauth2/src/OAuth2/Storage/JwtAccessToken.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-use OAuth2\Encryption\EncryptionInterface;
-use OAuth2\Encryption\Jwt;
-
-/**
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-class JwtAccessToken implements JwtAccessTokenInterface
-{
- protected $publicKeyStorage;
- protected $tokenStorage;
- protected $encryptionUtil;
-
- /**
- * @param OAuth2\Encryption\PublicKeyInterface $publicKeyStorage the public key encryption to use
- * @param OAuth2\Storage\AccessTokenInterface $tokenStorage OPTIONAL persist the access token to another storage. This is useful if
- * you want to retain access token grant information somewhere, but
- * is not necessary when using this grant type.
- * @param OAuth2\Encryption\EncryptionInterface $encryptionUtil OPTIONAL class to use for "encode" and "decode" functions.
- */
- public function __construct(PublicKeyInterface $publicKeyStorage, AccessTokenInterface $tokenStorage = null, EncryptionInterface $encryptionUtil = null)
- {
- $this->publicKeyStorage = $publicKeyStorage;
- $this->tokenStorage = $tokenStorage;
- if (is_null($encryptionUtil)) {
- $encryptionUtil = new Jwt;
- }
- $this->encryptionUtil = $encryptionUtil;
- }
-
- public function getAccessToken($oauth_token)
- {
- // just decode the token, don't verify
- if (!$tokenData = $this->encryptionUtil->decode($oauth_token, null, false)) {
- return false;
- }
-
- $client_id = isset($tokenData['aud']) ? $tokenData['aud'] : null;
- $public_key = $this->publicKeyStorage->getPublicKey($client_id);
- $algorithm = $this->publicKeyStorage->getEncryptionAlgorithm($client_id);
-
- // now that we have the client_id, verify the token
- if (false === $this->encryptionUtil->decode($oauth_token, $public_key, array($algorithm))) {
- return false;
- }
-
- // normalize the JWT claims to the format expected by other components in this library
- return $this->convertJwtToOAuth2($tokenData);
- }
-
- public function setAccessToken($oauth_token, $client_id, $user_id, $expires, $scope = null)
- {
- if ($this->tokenStorage) {
- return $this->tokenStorage->setAccessToken($oauth_token, $client_id, $user_id, $expires, $scope);
- }
- }
-
- public function unsetAccessToken($access_token)
- {
- if ($this->tokenStorage) {
- return $this->tokenStorage->unsetAccessToken($access_token);
- }
- }
-
-
- // converts a JWT access token into an OAuth2-friendly format
- protected function convertJwtToOAuth2($tokenData)
- {
- $keyMapping = array(
- 'aud' => 'client_id',
- 'exp' => 'expires',
- 'sub' => 'user_id'
- );
-
- foreach ($keyMapping as $jwtKey => $oauth2Key) {
- if (isset($tokenData[$jwtKey])) {
- $tokenData[$oauth2Key] = $tokenData[$jwtKey];
- unset($tokenData[$jwtKey]);
- }
- }
-
- return $tokenData;
- }
-}
diff --git a/library/oauth2/src/OAuth2/Storage/JwtAccessTokenInterface.php b/library/oauth2/src/OAuth2/Storage/JwtAccessTokenInterface.php
deleted file mode 100644
index 3abb2aa2d..000000000
--- a/library/oauth2/src/OAuth2/Storage/JwtAccessTokenInterface.php
+++ /dev/null
@@ -1,14 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-/**
- * No specific methods, but allows the library to check "instanceof"
- * against interface rather than class
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-interface JwtAccessTokenInterface extends AccessTokenInterface
-{
-
-}
diff --git a/library/oauth2/src/OAuth2/Storage/JwtBearerInterface.php b/library/oauth2/src/OAuth2/Storage/JwtBearerInterface.php
deleted file mode 100644
index c83aa72ea..000000000
--- a/library/oauth2/src/OAuth2/Storage/JwtBearerInterface.php
+++ /dev/null
@@ -1,74 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-/**
- * Implement this interface to specify where the OAuth2 Server
- * should get the JWT key for clients
- *
- * @TODO consider extending ClientInterface, as this will almost always
- * be the same storage as retrieving clientData
- *
- * @author F21
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-interface JwtBearerInterface
-{
- /**
- * Get the public key associated with a client_id
- *
- * @param $client_id
- * Client identifier to be checked with.
- *
- * @return
- * STRING Return the public key for the client_id if it exists, and MUST return FALSE if it doesn't.
- */
- public function getClientKey($client_id, $subject);
-
- /**
- * Get a jti (JSON token identifier) by matching against the client_id, subject, audience and expiration.
- *
- * @param $client_id
- * Client identifier to match.
- *
- * @param $subject
- * The subject to match.
- *
- * @param $audience
- * The audience to match.
- *
- * @param $expiration
- * The expiration of the jti.
- *
- * @param $jti
- * The jti to match.
- *
- * @return
- * An associative array as below, and return NULL if the jti does not exist.
- * - issuer: Stored client identifier.
- * - subject: Stored subject.
- * - audience: Stored audience.
- * - expires: Stored expiration in unix timestamp.
- * - jti: The stored jti.
- */
- public function getJti($client_id, $subject, $audience, $expiration, $jti);
-
- /**
- * Store a used jti so that we can check against it to prevent replay attacks.
- * @param $client_id
- * Client identifier to insert.
- *
- * @param $subject
- * The subject to insert.
- *
- * @param $audience
- * The audience to insert.
- *
- * @param $expiration
- * The expiration of the jti.
- *
- * @param $jti
- * The jti to insert.
- */
- public function setJti($client_id, $subject, $audience, $expiration, $jti);
-}
diff --git a/library/oauth2/src/OAuth2/Storage/Memory.php b/library/oauth2/src/OAuth2/Storage/Memory.php
deleted file mode 100644
index 42d833ccb..000000000
--- a/library/oauth2/src/OAuth2/Storage/Memory.php
+++ /dev/null
@@ -1,381 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-use OAuth2\OpenID\Storage\UserClaimsInterface;
-use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
-
-/**
- * Simple in-memory storage for all storage types
- *
- * NOTE: This class should never be used in production, and is
- * a stub class for example use only
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-class Memory implements AuthorizationCodeInterface,
- UserCredentialsInterface,
- UserClaimsInterface,
- AccessTokenInterface,
- ClientCredentialsInterface,
- RefreshTokenInterface,
- JwtBearerInterface,
- ScopeInterface,
- PublicKeyInterface,
- OpenIDAuthorizationCodeInterface
-{
- public $authorizationCodes;
- public $userCredentials;
- public $clientCredentials;
- public $refreshTokens;
- public $accessTokens;
- public $jwt;
- public $jti;
- public $supportedScopes;
- public $defaultScope;
- public $keys;
-
- public function __construct($params = array())
- {
- $params = array_merge(array(
- 'authorization_codes' => array(),
- 'user_credentials' => array(),
- 'client_credentials' => array(),
- 'refresh_tokens' => array(),
- 'access_tokens' => array(),
- 'jwt' => array(),
- 'jti' => array(),
- 'default_scope' => null,
- 'supported_scopes' => array(),
- 'keys' => array(),
- ), $params);
-
- $this->authorizationCodes = $params['authorization_codes'];
- $this->userCredentials = $params['user_credentials'];
- $this->clientCredentials = $params['client_credentials'];
- $this->refreshTokens = $params['refresh_tokens'];
- $this->accessTokens = $params['access_tokens'];
- $this->jwt = $params['jwt'];
- $this->jti = $params['jti'];
- $this->supportedScopes = $params['supported_scopes'];
- $this->defaultScope = $params['default_scope'];
- $this->keys = $params['keys'];
- }
-
- /* AuthorizationCodeInterface */
- public function getAuthorizationCode($code)
- {
- if (!isset($this->authorizationCodes[$code])) {
- return false;
- }
-
- return array_merge(array(
- 'authorization_code' => $code,
- ), $this->authorizationCodes[$code]);
- }
-
- public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
- {
- $this->authorizationCodes[$code] = compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token');
-
- return true;
- }
-
- public function setAuthorizationCodes($authorization_codes)
- {
- $this->authorizationCodes = $authorization_codes;
- }
-
- public function expireAuthorizationCode($code)
- {
- unset($this->authorizationCodes[$code]);
- }
-
- /* UserCredentialsInterface */
- public function checkUserCredentials($username, $password)
- {
- $userDetails = $this->getUserDetails($username);
-
- return $userDetails && $userDetails['password'] && $userDetails['password'] === $password;
- }
-
- public function setUser($username, $password, $firstName = null, $lastName = null)
- {
- $this->userCredentials[$username] = array(
- 'password' => $password,
- 'first_name' => $firstName,
- 'last_name' => $lastName,
- );
-
- return true;
- }
-
- public function getUserDetails($username)
- {
- if (!isset($this->userCredentials[$username])) {
- return false;
- }
-
- return array_merge(array(
- 'user_id' => $username,
- 'password' => null,
- 'first_name' => null,
- 'last_name' => null,
- ), $this->userCredentials[$username]);
- }
-
- /* UserClaimsInterface */
- public function getUserClaims($user_id, $claims)
- {
- if (!$userDetails = $this->getUserDetails($user_id)) {
- return false;
- }
-
- $claims = explode(' ', trim($claims));
- $userClaims = array();
-
- // for each requested claim, if the user has the claim, set it in the response
- $validClaims = explode(' ', self::VALID_CLAIMS);
- foreach ($validClaims as $validClaim) {
- if (in_array($validClaim, $claims)) {
- if ($validClaim == 'address') {
- // address is an object with subfields
- $userClaims['address'] = $this->getUserClaim($validClaim, $userDetails['address'] ?: $userDetails);
- } else {
- $userClaims = array_merge($userClaims, $this->getUserClaim($validClaim, $userDetails));
- }
- }
- }
-
- return $userClaims;
- }
-
- protected function getUserClaim($claim, $userDetails)
- {
- $userClaims = array();
- $claimValuesString = constant(sprintf('self::%s_CLAIM_VALUES', strtoupper($claim)));
- $claimValues = explode(' ', $claimValuesString);
-
- foreach ($claimValues as $value) {
- $userClaims[$value] = isset($userDetails[$value]) ? $userDetails[$value] : null;
- }
-
- return $userClaims;
- }
-
- /* ClientCredentialsInterface */
- public function checkClientCredentials($client_id, $client_secret = null)
- {
- return isset($this->clientCredentials[$client_id]['client_secret']) && $this->clientCredentials[$client_id]['client_secret'] === $client_secret;
- }
-
- public function isPublicClient($client_id)
- {
- if (!isset($this->clientCredentials[$client_id])) {
- return false;
- }
-
- return empty($this->clientCredentials[$client_id]['client_secret']);
- }
-
- /* ClientInterface */
- public function getClientDetails($client_id)
- {
- if (!isset($this->clientCredentials[$client_id])) {
- return false;
- }
-
- $clientDetails = array_merge(array(
- 'client_id' => $client_id,
- 'client_secret' => null,
- 'redirect_uri' => null,
- 'scope' => null,
- ), $this->clientCredentials[$client_id]);
-
- return $clientDetails;
- }
-
- public function checkRestrictedGrantType($client_id, $grant_type)
- {
- if (isset($this->clientCredentials[$client_id]['grant_types'])) {
- $grant_types = explode(' ', $this->clientCredentials[$client_id]['grant_types']);
-
- return in_array($grant_type, $grant_types);
- }
-
- // if grant_types are not defined, then none are restricted
- return true;
- }
-
- public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
- {
- $this->clientCredentials[$client_id] = array(
- 'client_id' => $client_id,
- 'client_secret' => $client_secret,
- 'redirect_uri' => $redirect_uri,
- 'grant_types' => $grant_types,
- 'scope' => $scope,
- 'user_id' => $user_id,
- );
-
- return true;
- }
-
- /* RefreshTokenInterface */
- public function getRefreshToken($refresh_token)
- {
- return isset($this->refreshTokens[$refresh_token]) ? $this->refreshTokens[$refresh_token] : false;
- }
-
- public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
- {
- $this->refreshTokens[$refresh_token] = compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope');
-
- return true;
- }
-
- public function unsetRefreshToken($refresh_token)
- {
- if (isset($this->refreshTokens[$refresh_token])) {
- unset($this->refreshTokens[$refresh_token]);
-
- return true;
- }
-
- return false;
- }
-
- public function setRefreshTokens($refresh_tokens)
- {
- $this->refreshTokens = $refresh_tokens;
- }
-
- /* AccessTokenInterface */
- public function getAccessToken($access_token)
- {
- return isset($this->accessTokens[$access_token]) ? $this->accessTokens[$access_token] : false;
- }
-
- public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null, $id_token = null)
- {
- $this->accessTokens[$access_token] = compact('access_token', 'client_id', 'user_id', 'expires', 'scope', 'id_token');
-
- return true;
- }
-
- public function unsetAccessToken($access_token)
- {
- if (isset($this->accessTokens[$access_token])) {
- unset($this->accessTokens[$access_token]);
-
- return true;
- }
-
- return false;
- }
-
- public function scopeExists($scope)
- {
- $scope = explode(' ', trim($scope));
-
- return (count(array_diff($scope, $this->supportedScopes)) == 0);
- }
-
- public function getDefaultScope($client_id = null)
- {
- return $this->defaultScope;
- }
-
- /*JWTBearerInterface */
- public function getClientKey($client_id, $subject)
- {
- if (isset($this->jwt[$client_id])) {
- $jwt = $this->jwt[$client_id];
- if ($jwt) {
- if ($jwt["subject"] == $subject) {
- return $jwt["key"];
- }
- }
- }
-
- return false;
- }
-
- public function getClientScope($client_id)
- {
- if (!$clientDetails = $this->getClientDetails($client_id)) {
- return false;
- }
-
- if (isset($clientDetails['scope'])) {
- return $clientDetails['scope'];
- }
-
- return null;
- }
-
- public function getJti($client_id, $subject, $audience, $expires, $jti)
- {
- foreach ($this->jti as $storedJti) {
- if ($storedJti['issuer'] == $client_id && $storedJti['subject'] == $subject && $storedJti['audience'] == $audience && $storedJti['expires'] == $expires && $storedJti['jti'] == $jti) {
- return array(
- 'issuer' => $storedJti['issuer'],
- 'subject' => $storedJti['subject'],
- 'audience' => $storedJti['audience'],
- 'expires' => $storedJti['expires'],
- 'jti' => $storedJti['jti']
- );
- }
- }
-
- return null;
- }
-
- public function setJti($client_id, $subject, $audience, $expires, $jti)
- {
- $this->jti[] = array('issuer' => $client_id, 'subject' => $subject, 'audience' => $audience, 'expires' => $expires, 'jti' => $jti);
- }
-
- /*PublicKeyInterface */
- public function getPublicKey($client_id = null)
- {
- if (isset($this->keys[$client_id])) {
- return $this->keys[$client_id]['public_key'];
- }
-
- // use a global encryption pair
- if (isset($this->keys['public_key'])) {
- return $this->keys['public_key'];
- }
-
- return false;
- }
-
- public function getPrivateKey($client_id = null)
- {
- if (isset($this->keys[$client_id])) {
- return $this->keys[$client_id]['private_key'];
- }
-
- // use a global encryption pair
- if (isset($this->keys['private_key'])) {
- return $this->keys['private_key'];
- }
-
- return false;
- }
-
- public function getEncryptionAlgorithm($client_id = null)
- {
- if (isset($this->keys[$client_id]['encryption_algorithm'])) {
- return $this->keys[$client_id]['encryption_algorithm'];
- }
-
- // use a global encryption algorithm
- if (isset($this->keys['encryption_algorithm'])) {
- return $this->keys['encryption_algorithm'];
- }
-
- return 'RS256';
- }
-}
diff --git a/library/oauth2/src/OAuth2/Storage/Mongo.php b/library/oauth2/src/OAuth2/Storage/Mongo.php
deleted file mode 100644
index cef35e5e9..000000000
--- a/library/oauth2/src/OAuth2/Storage/Mongo.php
+++ /dev/null
@@ -1,339 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
-
-/**
- * Simple MongoDB storage for all storage types
- *
- * NOTE: This class is meant to get users started
- * quickly. If your application requires further
- * customization, extend this class or create your own.
- *
- * NOTE: Passwords are stored in plaintext, which is never
- * a good idea. Be sure to override this for your application
- *
- * @author Julien Chaumond <chaumond@gmail.com>
- */
-class Mongo implements AuthorizationCodeInterface,
- AccessTokenInterface,
- ClientCredentialsInterface,
- UserCredentialsInterface,
- RefreshTokenInterface,
- JwtBearerInterface,
- OpenIDAuthorizationCodeInterface
-{
- protected $db;
- protected $config;
-
- public function __construct($connection, $config = array())
- {
- if ($connection instanceof \MongoDB) {
- $this->db = $connection;
- } else {
- if (!is_array($connection)) {
- throw new \InvalidArgumentException('First argument to OAuth2\Storage\Mongo must be an instance of MongoDB or a configuration array');
- }
- $server = sprintf('mongodb://%s:%d', $connection['host'], $connection['port']);
- $m = new \MongoClient($server);
- $this->db = $m->{$connection['database']};
- }
-
- $this->config = array_merge(array(
- 'client_table' => 'oauth_clients',
- 'access_token_table' => 'oauth_access_tokens',
- 'refresh_token_table' => 'oauth_refresh_tokens',
- 'code_table' => 'oauth_authorization_codes',
- 'user_table' => 'oauth_users',
- 'jwt_table' => 'oauth_jwt',
- ), $config);
- }
-
- // Helper function to access a MongoDB collection by `type`:
- protected function collection($name)
- {
- return $this->db->{$this->config[$name]};
- }
-
- /* ClientCredentialsInterface */
- public function checkClientCredentials($client_id, $client_secret = null)
- {
- if ($result = $this->collection('client_table')->findOne(array('client_id' => $client_id))) {
- return $result['client_secret'] == $client_secret;
- }
-
- return false;
- }
-
- public function isPublicClient($client_id)
- {
- if (!$result = $this->collection('client_table')->findOne(array('client_id' => $client_id))) {
- return false;
- }
-
- return empty($result['client_secret']);
- }
-
- /* ClientInterface */
- public function getClientDetails($client_id)
- {
- $result = $this->collection('client_table')->findOne(array('client_id' => $client_id));
-
- return is_null($result) ? false : $result;
- }
-
- public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
- {
- if ($this->getClientDetails($client_id)) {
- $this->collection('client_table')->update(
- array('client_id' => $client_id),
- array('$set' => array(
- 'client_secret' => $client_secret,
- 'redirect_uri' => $redirect_uri,
- 'grant_types' => $grant_types,
- 'scope' => $scope,
- 'user_id' => $user_id,
- ))
- );
- } else {
- $client = array(
- 'client_id' => $client_id,
- 'client_secret' => $client_secret,
- 'redirect_uri' => $redirect_uri,
- 'grant_types' => $grant_types,
- 'scope' => $scope,
- 'user_id' => $user_id,
- );
- $this->collection('client_table')->insert($client);
- }
-
- return true;
- }
-
- public function checkRestrictedGrantType($client_id, $grant_type)
- {
- $details = $this->getClientDetails($client_id);
- if (isset($details['grant_types'])) {
- $grant_types = explode(' ', $details['grant_types']);
-
- return in_array($grant_type, $grant_types);
- }
-
- // if grant_types are not defined, then none are restricted
- return true;
- }
-
- /* AccessTokenInterface */
- public function getAccessToken($access_token)
- {
- $token = $this->collection('access_token_table')->findOne(array('access_token' => $access_token));
-
- return is_null($token) ? false : $token;
- }
-
- public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
- {
- // if it exists, update it.
- if ($this->getAccessToken($access_token)) {
- $this->collection('access_token_table')->update(
- array('access_token' => $access_token),
- array('$set' => array(
- 'client_id' => $client_id,
- 'expires' => $expires,
- 'user_id' => $user_id,
- 'scope' => $scope
- ))
- );
- } else {
- $token = array(
- 'access_token' => $access_token,
- 'client_id' => $client_id,
- 'expires' => $expires,
- 'user_id' => $user_id,
- 'scope' => $scope
- );
- $this->collection('access_token_table')->insert($token);
- }
-
- return true;
- }
-
- public function unsetAccessToken($access_token)
- {
- $result = $this->collection('access_token_table')->remove(array(
- 'access_token' => $access_token
- ), array('w' => 1));
-
- return $result['n'] > 0;
- }
-
-
- /* AuthorizationCodeInterface */
- public function getAuthorizationCode($code)
- {
- $code = $this->collection('code_table')->findOne(array('authorization_code' => $code));
-
- return is_null($code) ? false : $code;
- }
-
- public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
- {
- // if it exists, update it.
- if ($this->getAuthorizationCode($code)) {
- $this->collection('code_table')->update(
- array('authorization_code' => $code),
- array('$set' => array(
- 'client_id' => $client_id,
- 'user_id' => $user_id,
- 'redirect_uri' => $redirect_uri,
- 'expires' => $expires,
- 'scope' => $scope,
- 'id_token' => $id_token,
- ))
- );
- } else {
- $token = array(
- 'authorization_code' => $code,
- 'client_id' => $client_id,
- 'user_id' => $user_id,
- 'redirect_uri' => $redirect_uri,
- 'expires' => $expires,
- 'scope' => $scope,
- 'id_token' => $id_token,
- );
- $this->collection('code_table')->insert($token);
- }
-
- return true;
- }
-
- public function expireAuthorizationCode($code)
- {
- $this->collection('code_table')->remove(array('authorization_code' => $code));
-
- return true;
- }
-
- /* UserCredentialsInterface */
- public function checkUserCredentials($username, $password)
- {
- if ($user = $this->getUser($username)) {
- return $this->checkPassword($user, $password);
- }
-
- return false;
- }
-
- public function getUserDetails($username)
- {
- if ($user = $this->getUser($username)) {
- $user['user_id'] = $user['username'];
- }
-
- return $user;
- }
-
- /* RefreshTokenInterface */
- public function getRefreshToken($refresh_token)
- {
- $token = $this->collection('refresh_token_table')->findOne(array('refresh_token' => $refresh_token));
-
- return is_null($token) ? false : $token;
- }
-
- public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
- {
- $token = array(
- 'refresh_token' => $refresh_token,
- 'client_id' => $client_id,
- 'user_id' => $user_id,
- 'expires' => $expires,
- 'scope' => $scope
- );
- $this->collection('refresh_token_table')->insert($token);
-
- return true;
- }
-
- public function unsetRefreshToken($refresh_token)
- {
- $result = $this->collection('refresh_token_table')->remove(array(
- 'refresh_token' => $refresh_token
- ), array('w' => 1));
-
- return $result['n'] > 0;
- }
-
- // plaintext passwords are bad! Override this for your application
- protected function checkPassword($user, $password)
- {
- return $user['password'] == $password;
- }
-
- public function getUser($username)
- {
- $result = $this->collection('user_table')->findOne(array('username' => $username));
-
- return is_null($result) ? false : $result;
- }
-
- public function setUser($username, $password, $firstName = null, $lastName = null)
- {
- if ($this->getUser($username)) {
- $this->collection('user_table')->update(
- array('username' => $username),
- array('$set' => array(
- 'password' => $password,
- 'first_name' => $firstName,
- 'last_name' => $lastName
- ))
- );
- } else {
- $user = array(
- 'username' => $username,
- 'password' => $password,
- 'first_name' => $firstName,
- 'last_name' => $lastName
- );
- $this->collection('user_table')->insert($user);
- }
-
- return true;
- }
-
- public function getClientKey($client_id, $subject)
- {
- $result = $this->collection('jwt_table')->findOne(array(
- 'client_id' => $client_id,
- 'subject' => $subject
- ));
-
- return is_null($result) ? false : $result['key'];
- }
-
- public function getClientScope($client_id)
- {
- if (!$clientDetails = $this->getClientDetails($client_id)) {
- return false;
- }
-
- if (isset($clientDetails['scope'])) {
- return $clientDetails['scope'];
- }
-
- return null;
- }
-
- public function getJti($client_id, $subject, $audience, $expiration, $jti)
- {
- //TODO: Needs mongodb implementation.
- throw new \Exception('getJti() for the MongoDB driver is currently unimplemented.');
- }
-
- public function setJti($client_id, $subject, $audience, $expiration, $jti)
- {
- //TODO: Needs mongodb implementation.
- throw new \Exception('setJti() for the MongoDB driver is currently unimplemented.');
- }
-}
diff --git a/library/oauth2/src/OAuth2/Storage/Pdo.php b/library/oauth2/src/OAuth2/Storage/Pdo.php
deleted file mode 100644
index ae5107e29..000000000
--- a/library/oauth2/src/OAuth2/Storage/Pdo.php
+++ /dev/null
@@ -1,553 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-use OAuth2\OpenID\Storage\UserClaimsInterface;
-use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
-
-/**
- * Simple PDO storage for all storage types
- *
- * NOTE: This class is meant to get users started
- * quickly. If your application requires further
- * customization, extend this class or create your own.
- *
- * NOTE: Passwords are stored in plaintext, which is never
- * a good idea. Be sure to override this for your application
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-class Pdo implements
- AuthorizationCodeInterface,
- AccessTokenInterface,
- ClientCredentialsInterface,
- UserCredentialsInterface,
- RefreshTokenInterface,
- JwtBearerInterface,
- ScopeInterface,
- PublicKeyInterface,
- UserClaimsInterface,
- OpenIDAuthorizationCodeInterface
-{
- protected $db;
- protected $config;
-
- public function __construct($connection, $config = array())
- {
- if (!$connection instanceof \PDO) {
- if (is_string($connection)) {
- $connection = array('dsn' => $connection);
- }
- if (!is_array($connection)) {
- throw new \InvalidArgumentException('First argument to OAuth2\Storage\Pdo must be an instance of PDO, a DSN string, or a configuration array');
- }
- if (!isset($connection['dsn'])) {
- throw new \InvalidArgumentException('configuration array must contain "dsn"');
- }
- // merge optional parameters
- $connection = array_merge(array(
- 'username' => null,
- 'password' => null,
- 'options' => array(),
- ), $connection);
- $connection = new \PDO($connection['dsn'], $connection['username'], $connection['password'], $connection['options']);
- }
- $this->db = $connection;
-
- // debugging
- $connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
-
- $this->config = array_merge(array(
- 'client_table' => 'oauth_clients',
- 'access_token_table' => 'oauth_access_tokens',
- 'refresh_token_table' => 'oauth_refresh_tokens',
- 'code_table' => 'oauth_authorization_codes',
- 'user_table' => 'oauth_users',
- 'jwt_table' => 'oauth_jwt',
- 'jti_table' => 'oauth_jti',
- 'scope_table' => 'oauth_scopes',
- 'public_key_table' => 'oauth_public_keys',
- ), $config);
- }
-
- /* OAuth2\Storage\ClientCredentialsInterface */
- public function checkClientCredentials($client_id, $client_secret = null)
- {
- $stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table']));
- $stmt->execute(compact('client_id'));
- $result = $stmt->fetch(\PDO::FETCH_ASSOC);
-
- // make this extensible
- return $result && $result['client_secret'] == $client_secret;
- }
-
- public function isPublicClient($client_id)
- {
- $stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table']));
- $stmt->execute(compact('client_id'));
-
- if (!$result = $stmt->fetch(\PDO::FETCH_ASSOC)) {
- return false;
- }
-
- return empty($result['client_secret']);
- }
-
- /* OAuth2\Storage\ClientInterface */
- public function getClientDetails($client_id)
- {
- $stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table']));
- $stmt->execute(compact('client_id'));
-
- return $stmt->fetch(\PDO::FETCH_ASSOC);
- }
-
- public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
- {
- // if it exists, update it.
- if ($this->getClientDetails($client_id)) {
- $stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_secret=:client_secret, redirect_uri=:redirect_uri, grant_types=:grant_types, scope=:scope, user_id=:user_id where client_id=:client_id', $this->config['client_table']));
- } else {
- $stmt = $this->db->prepare(sprintf('INSERT INTO %s (client_id, client_secret, redirect_uri, grant_types, scope, user_id) VALUES (:client_id, :client_secret, :redirect_uri, :grant_types, :scope, :user_id)', $this->config['client_table']));
- }
-
- return $stmt->execute(compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id'));
- }
-
- public function checkRestrictedGrantType($client_id, $grant_type)
- {
- $details = $this->getClientDetails($client_id);
- if (isset($details['grant_types'])) {
- $grant_types = explode(' ', $details['grant_types']);
-
- return in_array($grant_type, (array) $grant_types);
- }
-
- // if grant_types are not defined, then none are restricted
- return true;
- }
-
- /* OAuth2\Storage\AccessTokenInterface */
- public function getAccessToken($access_token)
- {
- $stmt = $this->db->prepare(sprintf('SELECT * from %s where access_token = :access_token', $this->config['access_token_table']));
-
- $token = $stmt->execute(compact('access_token'));
- if ($token = $stmt->fetch(\PDO::FETCH_ASSOC)) {
- // convert date string back to timestamp
- $token['expires'] = strtotime($token['expires']);
- }
-
- return $token;
- }
-
- public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
- {
- // convert expires to datestring
- $expires = date('Y-m-d H:i:s', $expires);
-
- // if it exists, update it.
- if ($this->getAccessToken($access_token)) {
- $stmt = $this->db->prepare(sprintf('UPDATE %s SET client_id=:client_id, expires=:expires, user_id=:user_id, scope=:scope where access_token=:access_token', $this->config['access_token_table']));
- } else {
- $stmt = $this->db->prepare(sprintf('INSERT INTO %s (access_token, client_id, expires, user_id, scope) VALUES (:access_token, :client_id, :expires, :user_id, :scope)', $this->config['access_token_table']));
- }
-
- return $stmt->execute(compact('access_token', 'client_id', 'user_id', 'expires', 'scope'));
- }
-
- public function unsetAccessToken($access_token)
- {
- $stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE access_token = :access_token', $this->config['access_token_table']));
-
- $stmt->execute(compact('access_token'));
-
- return $stmt->rowCount() > 0;
- }
-
- /* OAuth2\Storage\AuthorizationCodeInterface */
- public function getAuthorizationCode($code)
- {
- $stmt = $this->db->prepare(sprintf('SELECT * from %s where authorization_code = :code', $this->config['code_table']));
- $stmt->execute(compact('code'));
-
- if ($code = $stmt->fetch(\PDO::FETCH_ASSOC)) {
- // convert date string back to timestamp
- $code['expires'] = strtotime($code['expires']);
- }
-
- return $code;
- }
-
- public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
- {
- if (func_num_args() > 6) {
- // we are calling with an id token
- return call_user_func_array(array($this, 'setAuthorizationCodeWithIdToken'), func_get_args());
- }
-
- // convert expires to datestring
- $expires = date('Y-m-d H:i:s', $expires);
-
- // if it exists, update it.
- if ($this->getAuthorizationCode($code)) {
- $stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_id=:client_id, user_id=:user_id, redirect_uri=:redirect_uri, expires=:expires, scope=:scope where authorization_code=:code', $this->config['code_table']));
- } else {
- $stmt = $this->db->prepare(sprintf('INSERT INTO %s (authorization_code, client_id, user_id, redirect_uri, expires, scope) VALUES (:code, :client_id, :user_id, :redirect_uri, :expires, :scope)', $this->config['code_table']));
- }
-
- return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope'));
- }
-
- private function setAuthorizationCodeWithIdToken($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
- {
- // convert expires to datestring
- $expires = date('Y-m-d H:i:s', $expires);
-
- // if it exists, update it.
- if ($this->getAuthorizationCode($code)) {
- $stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_id=:client_id, user_id=:user_id, redirect_uri=:redirect_uri, expires=:expires, scope=:scope, id_token =:id_token where authorization_code=:code', $this->config['code_table']));
- } else {
- $stmt = $this->db->prepare(sprintf('INSERT INTO %s (authorization_code, client_id, user_id, redirect_uri, expires, scope, id_token) VALUES (:code, :client_id, :user_id, :redirect_uri, :expires, :scope, :id_token)', $this->config['code_table']));
- }
-
- return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'));
- }
-
- public function expireAuthorizationCode($code)
- {
- $stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE authorization_code = :code', $this->config['code_table']));
-
- return $stmt->execute(compact('code'));
- }
-
- /* OAuth2\Storage\UserCredentialsInterface */
- public function checkUserCredentials($username, $password)
- {
- if ($user = $this->getUser($username)) {
- return $this->checkPassword($user, $password);
- }
-
- return false;
- }
-
- public function getUserDetails($username)
- {
- return $this->getUser($username);
- }
-
- /* UserClaimsInterface */
- public function getUserClaims($user_id, $claims)
- {
- if (!$userDetails = $this->getUserDetails($user_id)) {
- return false;
- }
-
- $claims = explode(' ', trim($claims));
- $userClaims = array();
-
- // for each requested claim, if the user has the claim, set it in the response
- $validClaims = explode(' ', self::VALID_CLAIMS);
- foreach ($validClaims as $validClaim) {
- if (in_array($validClaim, $claims)) {
- if ($validClaim == 'address') {
- // address is an object with subfields
- $userClaims['address'] = $this->getUserClaim($validClaim, $userDetails['address'] ?: $userDetails);
- } else {
- $userClaims = array_merge($userClaims, $this->getUserClaim($validClaim, $userDetails));
- }
- }
- }
-
- return $userClaims;
- }
-
- protected function getUserClaim($claim, $userDetails)
- {
- $userClaims = array();
- $claimValuesString = constant(sprintf('self::%s_CLAIM_VALUES', strtoupper($claim)));
- $claimValues = explode(' ', $claimValuesString);
-
- foreach ($claimValues as $value) {
- $userClaims[$value] = isset($userDetails[$value]) ? $userDetails[$value] : null;
- }
-
- return $userClaims;
- }
-
- /* OAuth2\Storage\RefreshTokenInterface */
- public function getRefreshToken($refresh_token)
- {
- $stmt = $this->db->prepare(sprintf('SELECT * FROM %s WHERE refresh_token = :refresh_token', $this->config['refresh_token_table']));
-
- $token = $stmt->execute(compact('refresh_token'));
- if ($token = $stmt->fetch(\PDO::FETCH_ASSOC)) {
- // convert expires to epoch time
- $token['expires'] = strtotime($token['expires']);
- }
-
- return $token;
- }
-
- public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
- {
- // convert expires to datestring
- $expires = date('Y-m-d H:i:s', $expires);
-
- $stmt = $this->db->prepare(sprintf('INSERT INTO %s (refresh_token, client_id, user_id, expires, scope) VALUES (:refresh_token, :client_id, :user_id, :expires, :scope)', $this->config['refresh_token_table']));
-
- return $stmt->execute(compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope'));
- }
-
- public function unsetRefreshToken($refresh_token)
- {
- $stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE refresh_token = :refresh_token', $this->config['refresh_token_table']));
-
- $stmt->execute(compact('refresh_token'));
-
- return $stmt->rowCount() > 0;
- }
-
- // plaintext passwords are bad! Override this for your application
- protected function checkPassword($user, $password)
- {
- return $user['password'] == $this->hashPassword($password);
- }
-
- // use a secure hashing algorithm when storing passwords. Override this for your application
- protected function hashPassword($password)
- {
- return sha1($password);
- }
-
- public function getUser($username)
- {
- $stmt = $this->db->prepare($sql = sprintf('SELECT * from %s where username=:username', $this->config['user_table']));
- $stmt->execute(array('username' => $username));
-
- if (!$userInfo = $stmt->fetch(\PDO::FETCH_ASSOC)) {
- return false;
- }
-
- // the default behavior is to use "username" as the user_id
- return array_merge(array(
- 'user_id' => $username
- ), $userInfo);
- }
-
- public function setUser($username, $password, $firstName = null, $lastName = null)
- {
- // do not store in plaintext
- $password = $this->hashPassword($password);
-
- // if it exists, update it.
- if ($this->getUser($username)) {
- $stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET password=:password, first_name=:firstName, last_name=:lastName where username=:username', $this->config['user_table']));
- } else {
- $stmt = $this->db->prepare(sprintf('INSERT INTO %s (username, password, first_name, last_name) VALUES (:username, :password, :firstName, :lastName)', $this->config['user_table']));
- }
-
- return $stmt->execute(compact('username', 'password', 'firstName', 'lastName'));
- }
-
- /* ScopeInterface */
- public function scopeExists($scope)
- {
- $scope = explode(' ', $scope);
- $whereIn = implode(',', array_fill(0, count($scope), '?'));
- $stmt = $this->db->prepare(sprintf('SELECT count(scope) as count FROM %s WHERE scope IN (%s)', $this->config['scope_table'], $whereIn));
- $stmt->execute($scope);
-
- if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) {
- return $result['count'] == count($scope);
- }
-
- return false;
- }
-
- public function getDefaultScope($client_id = null)
- {
- $stmt = $this->db->prepare(sprintf('SELECT scope FROM %s WHERE is_default=:is_default', $this->config['scope_table']));
- $stmt->execute(array('is_default' => true));
-
- if ($result = $stmt->fetchAll(\PDO::FETCH_ASSOC)) {
- $defaultScope = array_map(function ($row) {
- return $row['scope'];
- }, $result);
-
- return implode(' ', $defaultScope);
- }
-
- return null;
- }
-
- /* JWTBearerInterface */
- public function getClientKey($client_id, $subject)
- {
- $stmt = $this->db->prepare($sql = sprintf('SELECT public_key from %s where client_id=:client_id AND subject=:subject', $this->config['jwt_table']));
-
- $stmt->execute(array('client_id' => $client_id, 'subject' => $subject));
-
- return $stmt->fetchColumn();
- }
-
- public function getClientScope($client_id)
- {
- if (!$clientDetails = $this->getClientDetails($client_id)) {
- return false;
- }
-
- if (isset($clientDetails['scope'])) {
- return $clientDetails['scope'];
- }
-
- return null;
- }
-
- public function getJti($client_id, $subject, $audience, $expires, $jti)
- {
- $stmt = $this->db->prepare($sql = sprintf('SELECT * FROM %s WHERE issuer=:client_id AND subject=:subject AND audience=:audience AND expires=:expires AND jti=:jti', $this->config['jti_table']));
-
- $stmt->execute(compact('client_id', 'subject', 'audience', 'expires', 'jti'));
-
- if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) {
- return array(
- 'issuer' => $result['issuer'],
- 'subject' => $result['subject'],
- 'audience' => $result['audience'],
- 'expires' => $result['expires'],
- 'jti' => $result['jti'],
- );
- }
-
- return null;
- }
-
- public function setJti($client_id, $subject, $audience, $expires, $jti)
- {
- $stmt = $this->db->prepare(sprintf('INSERT INTO %s (issuer, subject, audience, expires, jti) VALUES (:client_id, :subject, :audience, :expires, :jti)', $this->config['jti_table']));
-
- return $stmt->execute(compact('client_id', 'subject', 'audience', 'expires', 'jti'));
- }
-
- /* PublicKeyInterface */
- public function getPublicKey($client_id = null)
- {
- $stmt = $this->db->prepare($sql = sprintf('SELECT public_key FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table']));
-
- $stmt->execute(compact('client_id'));
- if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) {
- return $result['public_key'];
- }
- }
-
- public function getPrivateKey($client_id = null)
- {
- $stmt = $this->db->prepare($sql = sprintf('SELECT private_key FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table']));
-
- $stmt->execute(compact('client_id'));
- if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) {
- return $result['private_key'];
- }
- }
-
- public function getEncryptionAlgorithm($client_id = null)
- {
- $stmt = $this->db->prepare($sql = sprintf('SELECT encryption_algorithm FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table']));
-
- $stmt->execute(compact('client_id'));
- if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) {
- return $result['encryption_algorithm'];
- }
-
- return 'RS256';
- }
-
- /**
- * DDL to create OAuth2 database and tables for PDO storage
- *
- * @see https://github.com/dsquier/oauth2-server-php-mysql
- */
- public function getBuildSql($dbName = 'oauth2_server_php')
- {
- $sql = "
- CREATE TABLE {$this->config['client_table']} (
- client_id VARCHAR(80) NOT NULL,
- client_secret VARCHAR(80),
- redirect_uri VARCHAR(2000),
- grant_types VARCHAR(80),
- scope VARCHAR(4000),
- user_id VARCHAR(80),
- PRIMARY KEY (client_id)
- );
-
- CREATE TABLE {$this->config['access_token_table']} (
- access_token VARCHAR(40) NOT NULL,
- client_id VARCHAR(80) NOT NULL,
- user_id VARCHAR(80),
- expires TIMESTAMP NOT NULL,
- scope VARCHAR(4000),
- PRIMARY KEY (access_token)
- );
-
- CREATE TABLE {$this->config['code_table']} (
- authorization_code VARCHAR(40) NOT NULL,
- client_id VARCHAR(80) NOT NULL,
- user_id VARCHAR(80),
- redirect_uri VARCHAR(2000),
- expires TIMESTAMP NOT NULL,
- scope VARCHAR(4000),
- id_token VARCHAR(1000),
- PRIMARY KEY (authorization_code)
- );
-
- CREATE TABLE {$this->config['refresh_token_table']} (
- refresh_token VARCHAR(40) NOT NULL,
- client_id VARCHAR(80) NOT NULL,
- user_id VARCHAR(80),
- expires TIMESTAMP NOT NULL,
- scope VARCHAR(4000),
- PRIMARY KEY (refresh_token)
- );
-
- CREATE TABLE {$this->config['user_table']} (
- username VARCHAR(80),
- password VARCHAR(80),
- first_name VARCHAR(80),
- last_name VARCHAR(80),
- email VARCHAR(80),
- email_verified BOOLEAN,
- scope VARCHAR(4000)
- );
-
- CREATE TABLE {$this->config['scope_table']} (
- scope VARCHAR(80) NOT NULL,
- is_default BOOLEAN,
- PRIMARY KEY (scope)
- );
-
- CREATE TABLE {$this->config['jwt_table']} (
- client_id VARCHAR(80) NOT NULL,
- subject VARCHAR(80),
- public_key VARCHAR(2000) NOT NULL
- );
-
- CREATE TABLE {$this->config['jti_table']} (
- issuer VARCHAR(80) NOT NULL,
- subject VARCHAR(80),
- audience VARCHAR(80),
- expires TIMESTAMP NOT NULL,
- jti VARCHAR(2000) NOT NULL
- );
-
- CREATE TABLE {$this->config['public_key_table']} (
- client_id VARCHAR(80),
- public_key VARCHAR(2000),
- private_key VARCHAR(2000),
- encryption_algorithm VARCHAR(100) DEFAULT 'RS256'
- )
-";
-
- return $sql;
- }
-}
diff --git a/library/oauth2/src/OAuth2/Storage/PublicKeyInterface.php b/library/oauth2/src/OAuth2/Storage/PublicKeyInterface.php
deleted file mode 100644
index 108418d3a..000000000
--- a/library/oauth2/src/OAuth2/Storage/PublicKeyInterface.php
+++ /dev/null
@@ -1,16 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-/**
- * Implement this interface to specify where the OAuth2 Server
- * should get public/private key information
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-interface PublicKeyInterface
-{
- public function getPublicKey($client_id = null);
- public function getPrivateKey($client_id = null);
- public function getEncryptionAlgorithm($client_id = null);
-}
diff --git a/library/oauth2/src/OAuth2/Storage/Redis.php b/library/oauth2/src/OAuth2/Storage/Redis.php
deleted file mode 100644
index e6294e22d..000000000
--- a/library/oauth2/src/OAuth2/Storage/Redis.php
+++ /dev/null
@@ -1,321 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
-
-/**
- * redis storage for all storage types
- *
- * To use, install "predis/predis" via composer
- *
- * Register client:
- * <code>
- * $storage = new OAuth2\Storage\Redis($redis);
- * $storage->setClientDetails($client_id, $client_secret, $redirect_uri);
- * </code>
- */
-class Redis implements AuthorizationCodeInterface,
- AccessTokenInterface,
- ClientCredentialsInterface,
- UserCredentialsInterface,
- RefreshTokenInterface,
- JwtBearerInterface,
- ScopeInterface,
- OpenIDAuthorizationCodeInterface
-{
-
- private $cache;
-
- /* The redis client */
- protected $redis;
-
- /* Configuration array */
- protected $config;
-
- /**
- * Redis Storage!
- *
- * @param \Predis\Client $redis
- * @param array $config
- */
- public function __construct($redis, $config=array())
- {
- $this->redis = $redis;
- $this->config = array_merge(array(
- 'client_key' => 'oauth_clients:',
- 'access_token_key' => 'oauth_access_tokens:',
- 'refresh_token_key' => 'oauth_refresh_tokens:',
- 'code_key' => 'oauth_authorization_codes:',
- 'user_key' => 'oauth_users:',
- 'jwt_key' => 'oauth_jwt:',
- 'scope_key' => 'oauth_scopes:',
- ), $config);
- }
-
- protected function getValue($key)
- {
- if ( isset($this->cache[$key]) ) {
- return $this->cache[$key];
- }
- $value = $this->redis->get($key);
- if ( isset($value) ) {
- return json_decode($value, true);
- } else {
- return false;
- }
- }
-
- protected function setValue($key, $value, $expire=0)
- {
- $this->cache[$key] = $value;
- $str = json_encode($value);
- if ($expire > 0) {
- $seconds = $expire - time();
- $ret = $this->redis->setex($key, $seconds, $str);
- } else {
- $ret = $this->redis->set($key, $str);
- }
-
- // check that the key was set properly
- // if this fails, an exception will usually thrown, so this step isn't strictly necessary
- return is_bool($ret) ? $ret : $ret->getPayload() == 'OK';
- }
-
- protected function expireValue($key)
- {
- unset($this->cache[$key]);
-
- return $this->redis->del($key);
- }
-
- /* AuthorizationCodeInterface */
- public function getAuthorizationCode($code)
- {
- return $this->getValue($this->config['code_key'] . $code);
- }
-
- public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
- {
- return $this->setValue(
- $this->config['code_key'] . $authorization_code,
- compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'),
- $expires
- );
- }
-
- public function expireAuthorizationCode($code)
- {
- $key = $this->config['code_key'] . $code;
- unset($this->cache[$key]);
-
- return $this->expireValue($key);
- }
-
- /* UserCredentialsInterface */
- public function checkUserCredentials($username, $password)
- {
- $user = $this->getUserDetails($username);
-
- return $user && $user['password'] === $password;
- }
-
- public function getUserDetails($username)
- {
- return $this->getUser($username);
- }
-
- public function getUser($username)
- {
- if (!$userInfo = $this->getValue($this->config['user_key'] . $username)) {
- return false;
- }
-
- // the default behavior is to use "username" as the user_id
- return array_merge(array(
- 'user_id' => $username,
- ), $userInfo);
- }
-
- public function setUser($username, $password, $first_name = null, $last_name = null)
- {
- return $this->setValue(
- $this->config['user_key'] . $username,
- compact('username', 'password', 'first_name', 'last_name')
- );
- }
-
- /* ClientCredentialsInterface */
- public function checkClientCredentials($client_id, $client_secret = null)
- {
- if (!$client = $this->getClientDetails($client_id)) {
- return false;
- }
-
- return isset($client['client_secret'])
- && $client['client_secret'] == $client_secret;
- }
-
- public function isPublicClient($client_id)
- {
- if (!$client = $this->getClientDetails($client_id)) {
- return false;
- }
-
- return empty($client['client_secret']);
- }
-
- /* ClientInterface */
- public function getClientDetails($client_id)
- {
- return $this->getValue($this->config['client_key'] . $client_id);
- }
-
- public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
- {
- return $this->setValue(
- $this->config['client_key'] . $client_id,
- compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id')
- );
- }
-
- public function checkRestrictedGrantType($client_id, $grant_type)
- {
- $details = $this->getClientDetails($client_id);
- if (isset($details['grant_types'])) {
- $grant_types = explode(' ', $details['grant_types']);
-
- return in_array($grant_type, (array) $grant_types);
- }
-
- // if grant_types are not defined, then none are restricted
- return true;
- }
-
- /* RefreshTokenInterface */
- public function getRefreshToken($refresh_token)
- {
- return $this->getValue($this->config['refresh_token_key'] . $refresh_token);
- }
-
- public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
- {
- return $this->setValue(
- $this->config['refresh_token_key'] . $refresh_token,
- compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope'),
- $expires
- );
- }
-
- public function unsetRefreshToken($refresh_token)
- {
- $result = $this->expireValue($this->config['refresh_token_key'] . $refresh_token);
-
- return $result > 0;
- }
-
- /* AccessTokenInterface */
- public function getAccessToken($access_token)
- {
- return $this->getValue($this->config['access_token_key'].$access_token);
- }
-
- public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
- {
- return $this->setValue(
- $this->config['access_token_key'].$access_token,
- compact('access_token', 'client_id', 'user_id', 'expires', 'scope'),
- $expires
- );
- }
-
- public function unsetAccessToken($access_token)
- {
- $result = $this->expireValue($this->config['access_token_key'] . $access_token);
-
- return $result > 0;
- }
-
- /* ScopeInterface */
- public function scopeExists($scope)
- {
- $scope = explode(' ', $scope);
-
- $result = $this->getValue($this->config['scope_key'].'supported:global');
-
- $supportedScope = explode(' ', (string) $result);
-
- return (count(array_diff($scope, $supportedScope)) == 0);
- }
-
- public function getDefaultScope($client_id = null)
- {
- if (is_null($client_id) || !$result = $this->getValue($this->config['scope_key'].'default:'.$client_id)) {
- $result = $this->getValue($this->config['scope_key'].'default:global');
- }
-
- return $result;
- }
-
- public function setScope($scope, $client_id = null, $type = 'supported')
- {
- if (!in_array($type, array('default', 'supported'))) {
- throw new \InvalidArgumentException('"$type" must be one of "default", "supported"');
- }
-
- if (is_null($client_id)) {
- $key = $this->config['scope_key'].$type.':global';
- } else {
- $key = $this->config['scope_key'].$type.':'.$client_id;
- }
-
- return $this->setValue($key, $scope);
- }
-
- /*JWTBearerInterface */
- public function getClientKey($client_id, $subject)
- {
- if (!$jwt = $this->getValue($this->config['jwt_key'] . $client_id)) {
- return false;
- }
-
- if (isset($jwt['subject']) && $jwt['subject'] == $subject) {
- return $jwt['key'];
- }
-
- return null;
- }
-
- public function setClientKey($client_id, $key, $subject = null)
- {
- return $this->setValue($this->config['jwt_key'] . $client_id, array(
- 'key' => $key,
- 'subject' => $subject
- ));
- }
-
- public function getClientScope($client_id)
- {
- if (!$clientDetails = $this->getClientDetails($client_id)) {
- return false;
- }
-
- if (isset($clientDetails['scope'])) {
- return $clientDetails['scope'];
- }
-
- return null;
- }
-
- public function getJti($client_id, $subject, $audience, $expiration, $jti)
- {
- //TODO: Needs redis implementation.
- throw new \Exception('getJti() for the Redis driver is currently unimplemented.');
- }
-
- public function setJti($client_id, $subject, $audience, $expiration, $jti)
- {
- //TODO: Needs redis implementation.
- throw new \Exception('setJti() for the Redis driver is currently unimplemented.');
- }
-}
diff --git a/library/oauth2/src/OAuth2/Storage/RefreshTokenInterface.php b/library/oauth2/src/OAuth2/Storage/RefreshTokenInterface.php
deleted file mode 100644
index 0273f2125..000000000
--- a/library/oauth2/src/OAuth2/Storage/RefreshTokenInterface.php
+++ /dev/null
@@ -1,82 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-/**
- * Implement this interface to specify where the OAuth2 Server
- * should get/save refresh tokens for the "Refresh Token"
- * grant type
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-interface RefreshTokenInterface
-{
- /**
- * Grant refresh access tokens.
- *
- * Retrieve the stored data for the given refresh token.
- *
- * Required for OAuth2::GRANT_TYPE_REFRESH_TOKEN.
- *
- * @param $refresh_token
- * Refresh token to be check with.
- *
- * @return
- * An associative array as below, and NULL if the refresh_token is
- * invalid:
- * - refresh_token: Refresh token identifier.
- * - client_id: Client identifier.
- * - user_id: User identifier.
- * - expires: Expiration unix timestamp, or 0 if the token doesn't expire.
- * - scope: (optional) Scope values in space-separated string.
- *
- * @see http://tools.ietf.org/html/rfc6749#section-6
- *
- * @ingroup oauth2_section_6
- */
- public function getRefreshToken($refresh_token);
-
- /**
- * Take the provided refresh token values and store them somewhere.
- *
- * This function should be the storage counterpart to getRefreshToken().
- *
- * If storage fails for some reason, we're not currently checking for
- * any sort of success/failure, so you should bail out of the script
- * and provide a descriptive fail message.
- *
- * Required for OAuth2::GRANT_TYPE_REFRESH_TOKEN.
- *
- * @param $refresh_token
- * Refresh token to be stored.
- * @param $client_id
- * Client identifier to be stored.
- * @param $user_id
- * User identifier to be stored.
- * @param $expires
- * Expiration timestamp to be stored. 0 if the token doesn't expire.
- * @param $scope
- * (optional) Scopes to be stored in space-separated string.
- *
- * @ingroup oauth2_section_6
- */
- public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null);
-
- /**
- * Expire a used refresh token.
- *
- * This is not explicitly required in the spec, but is almost implied.
- * After granting a new refresh token, the old one is no longer useful and
- * so should be forcibly expired in the data store so it can't be used again.
- *
- * If storage fails for some reason, we're not currently checking for
- * any sort of success/failure, so you should bail out of the script
- * and provide a descriptive fail message.
- *
- * @param $refresh_token
- * Refresh token to be expirse.
- *
- * @ingroup oauth2_section_6
- */
- public function unsetRefreshToken($refresh_token);
-}
diff --git a/library/oauth2/src/OAuth2/Storage/ScopeInterface.php b/library/oauth2/src/OAuth2/Storage/ScopeInterface.php
deleted file mode 100644
index a8292269b..000000000
--- a/library/oauth2/src/OAuth2/Storage/ScopeInterface.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-/**
- * Implement this interface to specify where the OAuth2 Server
- * should retrieve data involving the relevent scopes associated
- * with this implementation.
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-interface ScopeInterface
-{
- /**
- * Check if the provided scope exists.
- *
- * @param $scope
- * A space-separated string of scopes.
- *
- * @return
- * TRUE if it exists, FALSE otherwise.
- */
- public function scopeExists($scope);
-
- /**
- * The default scope to use in the event the client
- * does not request one. By returning "false", a
- * request_error is returned by the server to force a
- * scope request by the client. By returning "null",
- * opt out of requiring scopes
- *
- * @param $client_id
- * An optional client id that can be used to return customized default scopes.
- *
- * @return
- * string representation of default scope, null if
- * scopes are not defined, or false to force scope
- * request by the client
- *
- * ex:
- * 'default'
- * ex:
- * null
- */
- public function getDefaultScope($client_id = null);
-}
diff --git a/library/oauth2/src/OAuth2/Storage/UserCredentialsInterface.php b/library/oauth2/src/OAuth2/Storage/UserCredentialsInterface.php
deleted file mode 100644
index 6e0fd7bad..000000000
--- a/library/oauth2/src/OAuth2/Storage/UserCredentialsInterface.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-/**
- * Implement this interface to specify where the OAuth2 Server
- * should retrieve user credentials for the
- * "Resource Owner Password Credentials" grant type
- *
- * @author Brent Shaffer <bshafs at gmail dot com>
- */
-interface UserCredentialsInterface
-{
- /**
- * Grant access tokens for basic user credentials.
- *
- * Check the supplied username and password for validity.
- *
- * You can also use the $client_id param to do any checks required based
- * on a client, if you need that.
- *
- * Required for OAuth2::GRANT_TYPE_USER_CREDENTIALS.
- *
- * @param $username
- * Username to be check with.
- * @param $password
- * Password to be check with.
- *
- * @return
- * TRUE if the username and password are valid, and FALSE if it isn't.
- * Moreover, if the username and password are valid, and you want to
- *
- * @see http://tools.ietf.org/html/rfc6749#section-4.3
- *
- * @ingroup oauth2_section_4
- */
- public function checkUserCredentials($username, $password);
-
- /**
- * @return
- * ARRAY the associated "user_id" and optional "scope" values
- * This function MUST return FALSE if the requested user does not exist or is
- * invalid. "scope" is a space-separated list of restricted scopes.
- * @code
- * return array(
- * "user_id" => USER_ID, // REQUIRED user_id to be stored with the authorization code or access token
- * "scope" => SCOPE // OPTIONAL space-separated list of restricted scopes
- * );
- * @endcode
- */
- public function getUserDetails($username);
-}
diff --git a/library/oauth2/src/OAuth2/TokenType/Bearer.php b/library/oauth2/src/OAuth2/TokenType/Bearer.php
deleted file mode 100644
index 8ac8596ac..000000000
--- a/library/oauth2/src/OAuth2/TokenType/Bearer.php
+++ /dev/null
@@ -1,130 +0,0 @@
-<?php
-
-namespace OAuth2\TokenType;
-
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-
-/**
-*
-*/
-class Bearer implements TokenTypeInterface
-{
- private $config;
-
- public function __construct(array $config = array())
- {
- $this->config = array_merge(array(
- 'token_param_name' => 'access_token',
- 'token_bearer_header_name' => 'Bearer',
- ), $config);
- }
-
- public function getTokenType()
- {
- return 'Bearer';
- }
-
- /**
- * Check if the request has supplied token
- *
- * @see https://github.com/bshaffer/oauth2-server-php/issues/349#issuecomment-37993588
- */
- public function requestHasToken(RequestInterface $request)
- {
- $headers = $request->headers('AUTHORIZATION');
-
- // check the header, then the querystring, then the request body
- return !empty($headers) || (bool) ($request->request($this->config['token_param_name'])) || (bool) ($request->query($this->config['token_param_name']));
- }
-
- /**
- * This is a convenience function that can be used to get the token, which can then
- * be passed to getAccessTokenData(). The constraints specified by the draft are
- * attempted to be adheared to in this method.
- *
- * As per the Bearer spec (draft 8, section 2) - there are three ways for a client
- * to specify the bearer token, in order of preference: Authorization Header,
- * POST and GET.
- *
- * NB: Resource servers MUST accept tokens via the Authorization scheme
- * (http://tools.ietf.org/html/rfc6750#section-2).
- *
- * @todo Should we enforce TLS/SSL in this function?
- *
- * @see http://tools.ietf.org/html/rfc6750#section-2.1
- * @see http://tools.ietf.org/html/rfc6750#section-2.2
- * @see http://tools.ietf.org/html/rfc6750#section-2.3
- *
- * Old Android version bug (at least with version 2.2)
- * @see http://code.google.com/p/android/issues/detail?id=6684
- *
- */
- public function getAccessTokenParameter(RequestInterface $request, ResponseInterface $response)
- {
- $headers = $request->headers('AUTHORIZATION');
-
- /**
- * Ensure more than one method is not used for including an
- * access token
- *
- * @see http://tools.ietf.org/html/rfc6750#section-3.1
- */
- $methodsUsed = !empty($headers) + (bool) ($request->query($this->config['token_param_name'])) + (bool) ($request->request($this->config['token_param_name']));
- if ($methodsUsed > 1) {
- $response->setError(400, 'invalid_request', 'Only one method may be used to authenticate at a time (Auth header, GET or POST)');
-
- return null;
- }
-
- /**
- * If no authentication is provided, set the status code
- * to 401 and return no other error information
- *
- * @see http://tools.ietf.org/html/rfc6750#section-3.1
- */
- if ($methodsUsed == 0) {
- $response->setStatusCode(401);
-
- return null;
- }
-
- // HEADER: Get the access token from the header
- if (!empty($headers)) {
- if (!preg_match('/' . $this->config['token_bearer_header_name'] . '\s(\S+)/i', $headers, $matches)) {
- $response->setError(400, 'invalid_request', 'Malformed auth header');
-
- return null;
- }
-
- return $matches[1];
- }
-
- if ($request->request($this->config['token_param_name'])) {
- // // POST: Get the token from POST data
- if (!in_array(strtolower($request->server('REQUEST_METHOD')), array('post', 'put'))) {
- $response->setError(400, 'invalid_request', 'When putting the token in the body, the method must be POST or PUT', '#section-2.2');
-
- return null;
- }
-
- $contentType = $request->server('CONTENT_TYPE');
- if (false !== $pos = strpos($contentType, ';')) {
- $contentType = substr($contentType, 0, $pos);
- }
-
- if ($contentType !== null && $contentType != 'application/x-www-form-urlencoded') {
- // IETF specifies content-type. NB: Not all webservers populate this _SERVER variable
- // @see http://tools.ietf.org/html/rfc6750#section-2.2
- $response->setError(400, 'invalid_request', 'The content type for POST requests must be "application/x-www-form-urlencoded"');
-
- return null;
- }
-
- return $request->request($this->config['token_param_name']);
- }
-
- // GET method
- return $request->query($this->config['token_param_name']);
- }
-}
diff --git a/library/oauth2/src/OAuth2/TokenType/Mac.php b/library/oauth2/src/OAuth2/TokenType/Mac.php
deleted file mode 100644
index fe6a86aa6..000000000
--- a/library/oauth2/src/OAuth2/TokenType/Mac.php
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-
-namespace OAuth2\TokenType;
-
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-
-/**
-* This is not yet supported!
-*/
-class Mac implements TokenTypeInterface
-{
- public function getTokenType()
- {
- return 'mac';
- }
-
- public function getAccessTokenParameter(RequestInterface $request, ResponseInterface $response)
- {
- throw new \LogicException("Not supported");
- }
-}
diff --git a/library/oauth2/src/OAuth2/TokenType/TokenTypeInterface.php b/library/oauth2/src/OAuth2/TokenType/TokenTypeInterface.php
deleted file mode 100644
index ad77d4a25..000000000
--- a/library/oauth2/src/OAuth2/TokenType/TokenTypeInterface.php
+++ /dev/null
@@ -1,21 +0,0 @@
-<?php
-
-namespace OAuth2\TokenType;
-
-use OAuth2\RequestInterface;
-use OAuth2\ResponseInterface;
-
-interface TokenTypeInterface
-{
- /**
- * Token type identification string
- *
- * ex: "bearer" or "mac"
- */
- public function getTokenType();
-
- /**
- * Retrieves the token string from the request object
- */
- public function getAccessTokenParameter(RequestInterface $request, ResponseInterface $response);
-}
diff --git a/library/oauth2/test/OAuth2/AutoloadTest.php b/library/oauth2/test/OAuth2/AutoloadTest.php
deleted file mode 100644
index 5901bdc42..000000000
--- a/library/oauth2/test/OAuth2/AutoloadTest.php
+++ /dev/null
@@ -1,16 +0,0 @@
-<?php
-
-namespace OAuth2;
-
-class AutoloadTest extends \PHPUnit_Framework_TestCase
-{
- public function testClassesExist()
- {
- // autoloader is called in test/bootstrap.php
- $this->assertTrue(class_exists('OAuth2\Server'));
- $this->assertTrue(class_exists('OAuth2\Request'));
- $this->assertTrue(class_exists('OAuth2\Response'));
- $this->assertTrue(class_exists('OAuth2\GrantType\UserCredentials'));
- $this->assertTrue(interface_exists('OAuth2\Storage\AccessTokenInterface'));
- }
-}
diff --git a/library/oauth2/test/OAuth2/Controller/AuthorizeControllerTest.php b/library/oauth2/test/OAuth2/Controller/AuthorizeControllerTest.php
deleted file mode 100644
index 3bfc760e4..000000000
--- a/library/oauth2/test/OAuth2/Controller/AuthorizeControllerTest.php
+++ /dev/null
@@ -1,492 +0,0 @@
-<?php
-
-namespace OAuth2\Controller;
-
-use OAuth2\Storage\Memory;
-use OAuth2\Scope;
-use OAuth2\Storage\Bootstrap;
-use OAuth2\Server;
-use OAuth2\GrantType\AuthorizationCode;
-use OAuth2\Request;
-use OAuth2\Response;
-use OAuth2\Request\TestRequest;
-
-class AuthorizeControllerTest extends \PHPUnit_Framework_TestCase
-{
- public function testNoClientIdResponse()
- {
- $server = $this->getTestServer();
- $request = new Request();
- $server->handleAuthorizeRequest($request, $response = new Response(), false);
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_client');
- $this->assertEquals($response->getParameter('error_description'), 'No client id supplied');
- }
-
- public function testInvalidClientIdResponse()
- {
- $server = $this->getTestServer();
- $request = new Request(array(
- 'client_id' => 'Fake Client ID', // invalid client id
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), false);
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_client');
- $this->assertEquals($response->getParameter('error_description'), 'The client id supplied is invalid');
- }
-
- public function testNoRedirectUriSuppliedOrStoredResponse()
- {
- $server = $this->getTestServer();
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), false);
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_uri');
- $this->assertEquals($response->getParameter('error_description'), 'No redirect URI was supplied or stored');
- }
-
- public function testNoResponseTypeResponse()
- {
- $server = $this->getTestServer();
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- 'redirect_uri' => 'http://adobe.com', // valid redirect URI
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), false);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $location = $response->getHttpHeader('Location');
- $parts = parse_url($location);
- parse_str($parts['query'], $query);
-
- $this->assertEquals($query['error'], 'invalid_request');
- $this->assertEquals($query['error_description'], 'Invalid or missing response type');
- }
-
- public function testInvalidResponseTypeResponse()
- {
- $server = $this->getTestServer();
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- 'redirect_uri' => 'http://adobe.com', // valid redirect URI
- 'response_type' => 'invalid', // invalid response type
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), false);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $location = $response->getHttpHeader('Location');
- $parts = parse_url($location);
- parse_str($parts['query'], $query);
-
- $this->assertEquals($query['error'], 'invalid_request');
- $this->assertEquals($query['error_description'], 'Invalid or missing response type');
- }
-
- public function testRedirectUriFragmentResponse()
- {
- $server = $this->getTestServer();
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- 'redirect_uri' => 'http://adobe.com#fragment', // valid redirect URI
- 'response_type' => 'code', // invalid response type
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_uri');
- $this->assertEquals($response->getParameter('error_description'), 'The redirect URI must not contain a fragment');
- }
-
- public function testEnforceState()
- {
- $server = $this->getTestServer(array('enforce_state' => true));
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- 'redirect_uri' => 'http://adobe.com', // valid redirect URI
- 'response_type' => 'code',
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $location = $response->getHttpHeader('Location');
- $parts = parse_url($location);
- parse_str($parts['query'], $query);
-
- $this->assertEquals($query['error'], 'invalid_request');
- $this->assertEquals($query['error_description'], 'The state parameter is required');
- }
-
- public function testDoNotEnforceState()
- {
- $server = $this->getTestServer(array('enforce_state' => false));
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- 'redirect_uri' => 'http://adobe.com', // valid redirect URI
- 'response_type' => 'code',
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $this->assertNotContains('error', $response->getHttpHeader('Location'));
- }
-
- public function testEnforceScope()
- {
- $server = $this->getTestServer();
- $scopeStorage = new Memory(array('default_scope' => false, 'supported_scopes' => array('testscope')));
- $server->setScopeUtil(new Scope($scopeStorage));
-
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- 'redirect_uri' => 'http://adobe.com', // valid redirect URI
- 'response_type' => 'code',
- 'state' => 'xyz',
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $parts = parse_url($response->getHttpHeader('Location'));
- parse_str($parts['query'], $query);
-
- $this->assertEquals($query['error'], 'invalid_client');
- $this->assertEquals($query['error_description'], 'This application requires you specify a scope parameter');
-
- $request->query['scope'] = 'testscope';
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $this->assertNotContains('error', $response->getHttpHeader('Location'));
- }
-
- public function testInvalidRedirectUri()
- {
- $server = $this->getTestServer();
- $request = new Request(array(
- 'client_id' => 'Test Client ID with Redirect Uri', // valid client id
- 'redirect_uri' => 'http://adobe.com', // invalid redirect URI
- 'response_type' => 'code',
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'redirect_uri_mismatch');
- $this->assertEquals($response->getParameter('error_description'), 'The redirect URI provided is missing or does not match');
- }
-
- public function testInvalidRedirectUriApprovedByBuggyRegisteredUri()
- {
- $server = $this->getTestServer();
- $server->setConfig('require_exact_redirect_uri', false);
- $request = new Request(array(
- 'client_id' => 'Test Client ID with Buggy Redirect Uri', // valid client id
- 'redirect_uri' => 'http://adobe.com', // invalid redirect URI
- 'response_type' => 'code',
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'redirect_uri_mismatch');
- $this->assertEquals($response->getParameter('error_description'), 'The redirect URI provided is missing or does not match');
- }
-
- public function testNoRedirectUriWithMultipleRedirectUris()
- {
- $server = $this->getTestServer();
-
- // create a request with no "redirect_uri" in querystring
- $request = new Request(array(
- 'client_id' => 'Test Client ID with Multiple Redirect Uris', // valid client id
- 'response_type' => 'code',
- ));
-
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_uri');
- $this->assertEquals($response->getParameter('error_description'), 'A redirect URI must be supplied when multiple redirect URIs are registered');
- }
-
- public function testRedirectUriWithValidRedirectUri()
- {
- $server = $this->getTestServer();
-
- // create a request with no "redirect_uri" in querystring
- $request = new Request(array(
- 'client_id' => 'Test Client ID with Redirect Uri Parts', // valid client id
- 'response_type' => 'code',
- 'redirect_uri' => 'http://user:pass@brentertainment.com:2222/authorize/cb?auth_type=oauth&test=true',
- 'state' => 'xyz',
- ));
-
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $this->assertContains('code', $response->getHttpHeader('Location'));
- }
-
- public function testRedirectUriWithDifferentQueryAndExactMatchRequired()
- {
- $server = $this->getTestServer(array('require_exact_redirect_uri' => true));
-
- // create a request with no "redirect_uri" in querystring
- $request = new Request(array(
- 'client_id' => 'Test Client ID with Redirect Uri Parts', // valid client id
- 'response_type' => 'code',
- 'redirect_uri' => 'http://user:pass@brentertainment.com:2222/authorize/cb?auth_type=oauth&test=true&hereisa=querystring',
- ));
-
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'redirect_uri_mismatch');
- $this->assertEquals($response->getParameter('error_description'), 'The redirect URI provided is missing or does not match');
- }
-
- public function testRedirectUriWithDifferentQueryAndExactMatchNotRequired()
- {
- $server = $this->getTestServer(array('require_exact_redirect_uri' => false));
-
- // create a request with no "redirect_uri" in querystring
- $request = new Request(array(
- 'client_id' => 'Test Client ID with Redirect Uri Parts', // valid client id
- 'response_type' => 'code',
- 'redirect_uri' => 'http://user:pass@brentertainment.com:2222/authorize/cb?auth_type=oauth&test=true&hereisa=querystring',
- 'state' => 'xyz',
- ));
-
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $this->assertContains('code', $response->getHttpHeader('Location'));
- }
-
- public function testMultipleRedirectUris()
- {
- $server = $this->getTestServer();
- $request = new Request(array(
- 'client_id' => 'Test Client ID with Multiple Redirect Uris', // valid client id
- 'redirect_uri' => 'http://brentertainment.com', // valid redirect URI
- 'response_type' => 'code',
- 'state' => 'xyz'
- ));
-
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
- $this->assertEquals($response->getStatusCode(), 302);
- $this->assertContains('code', $response->getHttpHeader('Location'));
-
- // call again with different (but still valid) redirect URI
- $request->query['redirect_uri'] = 'http://morehazards.com';
-
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
- $this->assertEquals($response->getStatusCode(), 302);
- $this->assertContains('code', $response->getHttpHeader('Location'));
- }
-
- /**
- * @see http://tools.ietf.org/html/rfc6749#section-4.1.3
- * @see https://github.com/bshaffer/oauth2-server-php/issues/163
- */
- public function testNoRedirectUriSuppliedDoesNotRequireTokenRedirectUri()
- {
- $server = $this->getTestServer();
- $request = new Request(array(
- 'client_id' => 'Test Client ID with Redirect Uri', // valid client id
- 'response_type' => 'code',
- 'state' => 'xyz',
- ));
-
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
- $this->assertEquals($response->getStatusCode(), 302);
- $this->assertContains('state', $response->getHttpHeader('Location'));
- $this->assertStringStartsWith('http://brentertainment.com?code=', $response->getHttpHeader('Location'));
-
- $parts = parse_url($response->getHttpHeader('Location'));
- parse_str($parts['query'], $query);
-
- // call token endpoint with no redirect_uri supplied
- $request = TestRequest::createPost(array(
- 'client_id' => 'Test Client ID with Redirect Uri', // valid client id
- 'client_secret' => 'TestSecret2',
- 'grant_type' => 'authorization_code',
- 'code' => $query['code'],
- ));
-
- $server->handleTokenRequest($request, $response = new Response(), true);
- $this->assertEquals($response->getStatusCode(), 200);
- $this->assertNotNull($response->getParameter('access_token'));
- }
-
- public function testUserDeniesAccessResponse()
- {
- $server = $this->getTestServer();
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- 'redirect_uri' => 'http://adobe.com', // valid redirect URI
- 'response_type' => 'code',
- 'state' => 'xyz',
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), false);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $location = $response->getHttpHeader('Location');
- $parts = parse_url($location);
- parse_str($parts['query'], $query);
-
- $this->assertEquals($query['error'], 'access_denied');
- $this->assertEquals($query['error_description'], 'The user denied access to your application');
- }
-
- public function testCodeQueryParamIsSet()
- {
- $server = $this->getTestServer();
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- 'redirect_uri' => 'http://adobe.com', // valid redirect URI
- 'response_type' => 'code',
- 'state' => 'xyz',
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $location = $response->getHttpHeader('Location');
- $parts = parse_url($location);
- parse_str($parts['query'], $query);
-
- $location = $response->getHttpHeader('Location');
- $parts = parse_url($location);
-
- $this->assertEquals('http', $parts['scheme']); // same as passed in to redirect_uri
- $this->assertEquals('adobe.com', $parts['host']); // same as passed in to redirect_uri
- $this->assertArrayHasKey('query', $parts);
- $this->assertFalse(isset($parts['fragment']));
-
- // assert fragment is in "application/x-www-form-urlencoded" format
- parse_str($parts['query'], $query);
- $this->assertNotNull($query);
- $this->assertArrayHasKey('code', $query);
-
- // ensure no id_token was saved, since the openid scope wasn't requested
- $storage = $server->getStorage('authorization_code');
- $code = $storage->getAuthorizationCode($query['code']);
- $this->assertTrue(empty($code['id_token']));
-
- // ensure no error was returned
- $this->assertFalse(isset($query['error']));
- $this->assertFalse(isset($query['error_description']));
- }
-
- public function testSuccessfulRequestReturnsStateParameter()
- {
- $server = $this->getTestServer(array('allow_implicit' => true));
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- 'redirect_uri' => 'http://adobe.com', // valid redirect URI
- 'response_type' => 'code',
- 'state' => 'test', // valid state string (just needs to be passed back to us)
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 302);
-
- $location = $response->getHttpHeader('Location');
- $parts = parse_url($location);
- $this->assertArrayHasKey('query', $parts);
- parse_str($parts['query'], $query);
-
- $this->assertArrayHasKey('state', $query);
- $this->assertEquals($query['state'], 'test');
-
- // ensure no error was returned
- $this->assertFalse(isset($query['error']));
- $this->assertFalse(isset($query['error_description']));
- }
-
- public function testSuccessfulRequestStripsExtraParameters()
- {
- $server = $this->getTestServer(array('allow_implicit' => true));
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- 'redirect_uri' => 'http://adobe.com', // valid redirect URI
- 'response_type' => 'code',
- 'state' => 'test', // valid state string (just needs to be passed back to us)
- 'fake' => 'something', // extra query param
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $location = $response->getHttpHeader('Location');
- $this->assertNotContains('error', $location);
-
- $parts = parse_url($location);
- $this->assertFalse(isset($parts['fake']));
- $this->assertArrayHasKey('query', $parts);
- parse_str($parts['query'], $query);
-
- $this->assertFalse(isset($parmas['fake']));
- $this->assertArrayHasKey('state', $query);
- $this->assertEquals($query['state'], 'test');
- }
-
- public function testSuccessfulOpenidConnectRequest()
- {
- $server = $this->getTestServer(array(
- 'use_openid_connect' => true,
- 'issuer' => 'bojanz',
- ));
-
- $request = new Request(array(
- 'client_id' => 'Test Client ID',
- 'redirect_uri' => 'http://adobe.com',
- 'response_type' => 'code',
- 'state' => 'xyz',
- 'scope' => 'openid',
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $location = $response->getHttpHeader('Location');
- $parts = parse_url($location);
- parse_str($parts['query'], $query);
-
- $location = $response->getHttpHeader('Location');
- $parts = parse_url($location);
- $this->assertArrayHasKey('query', $parts);
- $this->assertFalse(isset($parts['fragment']));
-
- // assert fragment is in "application/x-www-form-urlencoded" format
- parse_str($parts['query'], $query);
- $this->assertNotNull($query);
- $this->assertArrayHasKey('code', $query);
-
- // ensure no error was returned
- $this->assertFalse(isset($query['error']));
- $this->assertFalse(isset($query['error_description']));
-
- // confirm that the id_token has been created.
- $storage = $server->getStorage('authorization_code');
- $code = $storage->getAuthorizationCode($query['code']);
- $this->assertTrue(!empty($code['id_token']));
- }
-
- public function testCreateController()
- {
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $controller = new AuthorizeController($storage);
- }
-
- private function getTestServer($config = array())
- {
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $server = new Server($storage, $config);
-
- // Add the two types supported for authorization grant
- $server->addGrantType(new AuthorizationCode($storage));
-
- return $server;
- }
-}
diff --git a/library/oauth2/test/OAuth2/Controller/ResourceControllerTest.php b/library/oauth2/test/OAuth2/Controller/ResourceControllerTest.php
deleted file mode 100644
index ee6d96ff8..000000000
--- a/library/oauth2/test/OAuth2/Controller/ResourceControllerTest.php
+++ /dev/null
@@ -1,175 +0,0 @@
-<?php
-
-namespace OAuth2\Controller;
-
-use OAuth2\Storage\Bootstrap;
-use OAuth2\Server;
-use OAuth2\GrantType\AuthorizationCode;
-use OAuth2\Request;
-use OAuth2\Response;
-
-class ResourceControllerTest extends \PHPUnit_Framework_TestCase
-{
- public function testNoAccessToken()
- {
- $server = $this->getTestServer();
- $request = Request::createFromGlobals();
- $allow = $server->verifyResourceRequest($request, $response = new Response());
- $this->assertFalse($allow);
-
- $this->assertEquals($response->getStatusCode(), 401);
- $this->assertNull($response->getParameter('error'));
- $this->assertNull($response->getParameter('error_description'));
- }
-
- public function testMalformedHeader()
- {
- $server = $this->getTestServer();
- $request = Request::createFromGlobals();
- $request->headers['AUTHORIZATION'] = 'tH1s i5 B0gU5';
- $allow = $server->verifyResourceRequest($request, $response = new Response());
- $this->assertFalse($allow);
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_request');
- $this->assertEquals($response->getParameter('error_description'), 'Malformed auth header');
- }
-
- public function testMultipleTokensSubmitted()
- {
- $server = $this->getTestServer();
- $request = Request::createFromGlobals();
- $request->request['access_token'] = 'TEST';
- $request->query['access_token'] = 'TEST';
- $allow = $server->verifyResourceRequest($request, $response = new Response());
- $this->assertFalse($allow);
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_request');
- $this->assertEquals($response->getParameter('error_description'), 'Only one method may be used to authenticate at a time (Auth header, GET or POST)');
- }
-
- public function testInvalidRequestMethod()
- {
- $server = $this->getTestServer();
- $request = Request::createFromGlobals();
- $request->server['REQUEST_METHOD'] = 'GET';
- $request->request['access_token'] = 'TEST';
- $allow = $server->verifyResourceRequest($request, $response = new Response());
- $this->assertFalse($allow);
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_request');
- $this->assertEquals($response->getParameter('error_description'), 'When putting the token in the body, the method must be POST or PUT');
- }
-
- public function testInvalidContentType()
- {
- $server = $this->getTestServer();
- $request = Request::createFromGlobals();
- $request->server['REQUEST_METHOD'] = 'POST';
- $request->server['CONTENT_TYPE'] = 'application/json';
- $request->request['access_token'] = 'TEST';
- $allow = $server->verifyResourceRequest($request, $response = new Response());
- $this->assertFalse($allow);
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_request');
- $this->assertEquals($response->getParameter('error_description'), 'The content type for POST requests must be "application/x-www-form-urlencoded"');
- }
-
- public function testInvalidToken()
- {
- $server = $this->getTestServer();
- $request = Request::createFromGlobals();
- $request->headers['AUTHORIZATION'] = 'Bearer TESTTOKEN';
- $allow = $server->verifyResourceRequest($request, $response = new Response());
- $this->assertFalse($allow);
-
- $this->assertEquals($response->getStatusCode(), 401);
- $this->assertEquals($response->getParameter('error'), 'invalid_token');
- $this->assertEquals($response->getParameter('error_description'), 'The access token provided is invalid');
- }
-
- public function testExpiredToken()
- {
- $server = $this->getTestServer();
- $request = Request::createFromGlobals();
- $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-expired';
- $allow = $server->verifyResourceRequest($request, $response = new Response());
- $this->assertFalse($allow);
-
- $this->assertEquals($response->getStatusCode(), 401);
- $this->assertEquals($response->getParameter('error'), 'expired_token');
- $this->assertEquals($response->getParameter('error_description'), 'The access token provided has expired');
- }
-
- public function testOutOfScopeToken()
- {
- $server = $this->getTestServer();
- $request = Request::createFromGlobals();
- $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-scope';
- $scope = 'outofscope';
- $allow = $server->verifyResourceRequest($request, $response = new Response(), $scope);
- $this->assertFalse($allow);
-
- $this->assertEquals($response->getStatusCode(), 403);
- $this->assertEquals($response->getParameter('error'), 'insufficient_scope');
- $this->assertEquals($response->getParameter('error_description'), 'The request requires higher privileges than provided by the access token');
-
- // verify the "scope" has been set in the "WWW-Authenticate" header
- preg_match('/scope="(.*?)"/', $response->getHttpHeader('WWW-Authenticate'), $matches);
- $this->assertEquals(2, count($matches));
- $this->assertEquals($matches[1], 'outofscope');
- }
-
- public function testMalformedToken()
- {
- $server = $this->getTestServer();
- $request = Request::createFromGlobals();
- $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-malformed';
- $allow = $server->verifyResourceRequest($request, $response = new Response());
- $this->assertFalse($allow);
-
- $this->assertEquals($response->getStatusCode(), 401);
- $this->assertEquals($response->getParameter('error'), 'malformed_token');
- $this->assertEquals($response->getParameter('error_description'), 'Malformed token (missing "expires")');
- }
-
- public function testValidToken()
- {
- $server = $this->getTestServer();
- $request = Request::createFromGlobals();
- $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-scope';
- $allow = $server->verifyResourceRequest($request, $response = new Response());
- $this->assertTrue($allow);
- }
-
- public function testValidTokenWithScopeParam()
- {
- $server = $this->getTestServer();
- $request = Request::createFromGlobals();
- $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-scope';
- $request->query['scope'] = 'testscope';
- $allow = $server->verifyResourceRequest($request, $response = new Response());
- $this->assertTrue($allow);
- }
-
- public function testCreateController()
- {
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $tokenType = new \OAuth2\TokenType\Bearer();
- $controller = new ResourceController($tokenType, $storage);
- }
-
- private function getTestServer($config = array())
- {
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $server = new Server($storage, $config);
-
- // Add the two types supported for authorization grant
- $server->addGrantType(new AuthorizationCode($storage));
-
- return $server;
- }
-}
diff --git a/library/oauth2/test/OAuth2/Controller/TokenControllerTest.php b/library/oauth2/test/OAuth2/Controller/TokenControllerTest.php
deleted file mode 100644
index 4a217bd55..000000000
--- a/library/oauth2/test/OAuth2/Controller/TokenControllerTest.php
+++ /dev/null
@@ -1,289 +0,0 @@
-<?php
-
-namespace OAuth2\Controller;
-
-use OAuth2\Storage\Bootstrap;
-use OAuth2\Server;
-use OAuth2\GrantType\AuthorizationCode;
-use OAuth2\GrantType\ClientCredentials;
-use OAuth2\GrantType\UserCredentials;
-use OAuth2\Scope;
-use OAuth2\Request\TestRequest;
-use OAuth2\Response;
-
-class TokenControllerTest extends \PHPUnit_Framework_TestCase
-{
- public function testNoGrantType()
- {
- // add the test parameters in memory
- $server = $this->getTestServer();
- $server->handleTokenRequest(TestRequest::createPost(), $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_request');
- $this->assertEquals($response->getParameter('error_description'), 'The grant type was not specified in the request');
- }
-
- public function testInvalidGrantType()
- {
- // add the test parameters in memory
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'invalid_grant_type', // invalid grant type
- ));
- $server->handleTokenRequest($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'unsupported_grant_type');
- $this->assertEquals($response->getParameter('error_description'), 'Grant type "invalid_grant_type" not supported');
- }
-
- public function testNoClientId()
- {
- // add the test parameters in memory
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'code' => 'testcode',
- ));
- $server->handleTokenRequest($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_client');
- $this->assertEquals($response->getParameter('error_description'), 'Client credentials were not found in the headers or body');
- }
-
- public function testNoClientSecretWithConfidentialClient()
- {
- // add the test parameters in memory
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'code' => 'testcode',
- 'client_id' => 'Test Client ID', // valid client id
- ));
- $server->handleTokenRequest($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_client');
- $this->assertEquals($response->getParameter('error_description'), 'This client is invalid or must authenticate using a client secret');
- }
-
- public function testNoClientSecretWithEmptySecret()
- {
- // add the test parameters in memory
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'code' => 'testcode-empty-secret',
- 'client_id' => 'Test Client ID Empty Secret', // valid client id
- ));
- $server->handleTokenRequest($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 200);
- }
-
- public function testInvalidClientId()
- {
- // add the test parameters in memory
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'code' => 'testcode',
- 'client_id' => 'Fake Client ID', // invalid client id
- 'client_secret' => 'TestSecret', // valid client secret
- ));
- $server->handleTokenRequest($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_client');
- $this->assertEquals($response->getParameter('error_description'), 'The client credentials are invalid');
- }
-
- public function testInvalidClientSecret()
- {
- // add the test parameters in memory
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'code' => 'testcode',
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'Fake Client Secret', // invalid client secret
- ));
- $server->handleTokenRequest($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_client');
- $this->assertEquals($response->getParameter('error_description'), 'The client credentials are invalid');
- }
-
- public function testValidTokenResponse()
- {
- // add the test parameters in memory
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'code' => 'testcode', // valid authorization code
- ));
- $server->handleTokenRequest($request, $response = new Response());
-
- $this->assertTrue($response instanceof Response);
- $this->assertEquals($response->getStatusCode(), 200);
- $this->assertNull($response->getParameter('error'));
- $this->assertNull($response->getParameter('error_description'));
- $this->assertNotNull($response->getParameter('access_token'));
- $this->assertNotNull($response->getParameter('expires_in'));
- $this->assertNotNull($response->getParameter('token_type'));
- }
-
- public function testValidClientIdScope()
- {
- // add the test parameters in memory
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'code' => 'testcode',
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'scope' => 'clientscope1 clientscope2'
- ));
- $server->handleTokenRequest($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 200);
- $this->assertNull($response->getParameter('error'));
- $this->assertNull($response->getParameter('error_description'));
- $this->assertEquals('clientscope1 clientscope2', $response->getParameter('scope'));
- }
-
- public function testInvalidClientIdScope()
- {
- // add the test parameters in memory
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'code' => 'testcode-with-scope',
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'scope' => 'clientscope3'
- ));
- $server->handleTokenRequest($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_scope');
- $this->assertEquals($response->getParameter('error_description'), 'The scope requested is invalid for this request');
- }
-
- public function testEnforceScope()
- {
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $server = new Server($storage);
- $server->addGrantType(new ClientCredentials($storage));
-
- $scope = new Scope(array(
- 'default_scope' => false,
- 'supported_scopes' => array('testscope')
- ));
- $server->setScopeUtil($scope);
-
- $request = TestRequest::createPost(array(
- 'grant_type' => 'client_credentials', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- ));
- $response = $server->handleTokenRequest($request);
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_scope');
- $this->assertEquals($response->getParameter('error_description'), 'This application requires you specify a scope parameter');
- }
-
- public function testCanReceiveAccessTokenUsingPasswordGrantTypeWithoutClientSecret()
- {
- // add the test parameters in memory
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $server = new Server($storage);
- $server->addGrantType(new UserCredentials($storage));
-
- $request = TestRequest::createPost(array(
- 'grant_type' => 'password', // valid grant type
- 'client_id' => 'Test Client ID For Password Grant', // valid client id
- 'username' => 'johndoe', // valid username
- 'password' => 'password', // valid password for username
- ));
- $server->handleTokenRequest($request, $response = new Response());
-
- $this->assertTrue($response instanceof Response);
- $this->assertEquals(200, $response->getStatusCode(), var_export($response, 1));
- $this->assertNull($response->getParameter('error'));
- $this->assertNull($response->getParameter('error_description'));
- $this->assertNotNull($response->getParameter('access_token'));
- $this->assertNotNull($response->getParameter('expires_in'));
- $this->assertNotNull($response->getParameter('token_type'));
- }
-
- public function testInvalidTokenTypeHintForRevoke()
- {
- $server = $this->getTestServer();
-
- $request = TestRequest::createPost(array(
- 'token_type_hint' => 'foo',
- 'token' => 'sometoken'
- ));
-
- $server->handleRevokeRequest($request, $response = new Response());
-
- $this->assertTrue($response instanceof Response);
- $this->assertEquals(400, $response->getStatusCode(), var_export($response, 1));
- $this->assertEquals($response->getParameter('error'), 'invalid_request');
- $this->assertEquals($response->getParameter('error_description'), 'Token type hint must be either \'access_token\' or \'refresh_token\'');
- }
-
- public function testMissingTokenForRevoke()
- {
- $server = $this->getTestServer();
-
- $request = TestRequest::createPost(array(
- 'token_type_hint' => 'access_token'
- ));
-
- $server->handleRevokeRequest($request, $response = new Response());
- $this->assertTrue($response instanceof Response);
- $this->assertEquals(400, $response->getStatusCode(), var_export($response, 1));
- $this->assertEquals($response->getParameter('error'), 'invalid_request');
- $this->assertEquals($response->getParameter('error_description'), 'Missing token parameter to revoke');
- }
-
- public function testInvalidRequestMethodForRevoke()
- {
- $server = $this->getTestServer();
-
- $request = new TestRequest();
- $request->setQuery(array(
- 'token_type_hint' => 'access_token'
- ));
-
- $server->handleRevokeRequest($request, $response = new Response());
- $this->assertTrue($response instanceof Response);
- $this->assertEquals(405, $response->getStatusCode(), var_export($response, 1));
- $this->assertEquals($response->getParameter('error'), 'invalid_request');
- $this->assertEquals($response->getParameter('error_description'), 'The request method must be POST when revoking an access token');
- }
-
- public function testCreateController()
- {
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $accessToken = new \OAuth2\ResponseType\AccessToken($storage);
- $controller = new TokenController($accessToken, $storage);
- }
-
- private function getTestServer()
- {
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $server = new Server($storage);
- $server->addGrantType(new AuthorizationCode($storage));
-
- return $server;
- }
-}
diff --git a/library/oauth2/test/OAuth2/Encryption/FirebaseJwtTest.php b/library/oauth2/test/OAuth2/Encryption/FirebaseJwtTest.php
deleted file mode 100644
index d34136767..000000000
--- a/library/oauth2/test/OAuth2/Encryption/FirebaseJwtTest.php
+++ /dev/null
@@ -1,102 +0,0 @@
-<?php
-
-namespace OAuth2\Encryption;
-
-use OAuth2\Storage\Bootstrap;
-
-class FirebaseJwtTest extends \PHPUnit_Framework_TestCase
-{
- private $privateKey;
-
- public function setUp()
- {
- $this->privateKey = <<<EOD
------BEGIN RSA PRIVATE KEY-----
-MIICXAIBAAKBgQC5/SxVlE8gnpFqCxgl2wjhzY7ucEi00s0kUg3xp7lVEvgLgYcA
-nHiWp+gtSjOFfH2zsvpiWm6Lz5f743j/FEzHIO1owR0p4d9pOaJK07d01+RzoQLO
-IQAgXrr4T1CCWUesncwwPBVCyy2Mw3Nmhmr9MrF8UlvdRKBxriRnlP3qJQIDAQAB
-AoGAVgJJVU4fhYMu1e5JfYAcTGfF+Gf+h3iQm4JCpoUcxMXf5VpB9ztk3K7LRN5y
-kwFuFALpnUAarRcUPs0D8FoP4qBluKksbAtgHkO7bMSH9emN+mH4le4qpFlR7+P1
-3fLE2Y19IBwPwEfClC+TpJvuog6xqUYGPlg6XLq/MxQUB4ECQQDgovP1v+ONSeGS
-R+NgJTR47noTkQT3M2izlce/OG7a+O0yw6BOZjNXqH2wx3DshqMcPUFrTjibIClP
-l/tEQ3ShAkEA0/TdBYDtXpNNjqg0R9GVH2pw7Kh68ne6mZTuj0kCgFYpUF6L6iMm
-zXamIJ51rTDsTyKTAZ1JuAhAsK/M2BbDBQJAKQ5fXEkIA+i+64dsDUR/hKLBeRYG
-PFAPENONQGvGBwt7/s02XV3cgGbxIgAxqWkqIp0neb9AJUoJgtyaNe3GQQJANoL4
-QQ0af0NVJAZgg8QEHTNL3aGrFSbzx8IE5Lb7PLRsJa5bP5lQxnDoYuU+EI/Phr62
-niisp/b/ZDGidkTMXQJBALeRsH1I+LmICAvWXpLKa9Gv0zGCwkuIJLiUbV9c6CVh
-suocCAteQwL5iW2gA4AnYr5OGeHFsEl7NCQcwfPZpJ0=
------END RSA PRIVATE KEY-----
-EOD;
- }
-
- /** @dataProvider provideClientCredentials */
- public function testJwtUtil($client_id, $client_key)
- {
- $jwtUtil = new FirebaseJwt();
-
- $params = array(
- 'iss' => $client_id,
- 'exp' => time() + 1000,
- 'iat' => time(),
- 'sub' => 'testuser@ourdomain.com',
- 'aud' => 'http://myapp.com/oauth/auth',
- 'scope' => null,
- );
-
- $encoded = $jwtUtil->encode($params, $this->privateKey, 'RS256');
-
- // test BC behaviour of trusting the algorithm in the header
- $payload = $jwtUtil->decode($encoded, $client_key, array('RS256'));
- $this->assertEquals($params, $payload);
-
- // test BC behaviour of not verifying by passing false
- $payload = $jwtUtil->decode($encoded, $client_key, false);
- $this->assertEquals($params, $payload);
-
- // test the new restricted algorithms header
- $payload = $jwtUtil->decode($encoded, $client_key, array('RS256'));
- $this->assertEquals($params, $payload);
- }
-
- public function testInvalidJwt()
- {
- $jwtUtil = new FirebaseJwt();
-
- $this->assertFalse($jwtUtil->decode('goob'));
- $this->assertFalse($jwtUtil->decode('go.o.b'));
- }
-
- /** @dataProvider provideClientCredentials */
- public function testInvalidJwtHeader($client_id, $client_key)
- {
- $jwtUtil = new FirebaseJwt();
-
- $params = array(
- 'iss' => $client_id,
- 'exp' => time() + 1000,
- 'iat' => time(),
- 'sub' => 'testuser@ourdomain.com',
- 'aud' => 'http://myapp.com/oauth/auth',
- 'scope' => null,
- );
-
- // testing for algorithm tampering when only RSA256 signing is allowed
- // @see https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
- $tampered = $jwtUtil->encode($params, $client_key, 'HS256');
-
- $payload = $jwtUtil->decode($tampered, $client_key, array('RS256'));
-
- $this->assertFalse($payload);
- }
-
- public function provideClientCredentials()
- {
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $client_id = 'Test Client ID';
- $client_key = $storage->getClientKey($client_id, "testuser@ourdomain.com");
-
- return array(
- array($client_id, $client_key),
- );
- }
-}
diff --git a/library/oauth2/test/OAuth2/Encryption/JwtTest.php b/library/oauth2/test/OAuth2/Encryption/JwtTest.php
deleted file mode 100644
index 214eebac8..000000000
--- a/library/oauth2/test/OAuth2/Encryption/JwtTest.php
+++ /dev/null
@@ -1,102 +0,0 @@
-<?php
-
-namespace OAuth2\Encryption;
-
-use OAuth2\Storage\Bootstrap;
-
-class JwtTest extends \PHPUnit_Framework_TestCase
-{
- private $privateKey;
-
- public function setUp()
- {
- $this->privateKey = <<<EOD
------BEGIN RSA PRIVATE KEY-----
-MIICXAIBAAKBgQC5/SxVlE8gnpFqCxgl2wjhzY7ucEi00s0kUg3xp7lVEvgLgYcA
-nHiWp+gtSjOFfH2zsvpiWm6Lz5f743j/FEzHIO1owR0p4d9pOaJK07d01+RzoQLO
-IQAgXrr4T1CCWUesncwwPBVCyy2Mw3Nmhmr9MrF8UlvdRKBxriRnlP3qJQIDAQAB
-AoGAVgJJVU4fhYMu1e5JfYAcTGfF+Gf+h3iQm4JCpoUcxMXf5VpB9ztk3K7LRN5y
-kwFuFALpnUAarRcUPs0D8FoP4qBluKksbAtgHkO7bMSH9emN+mH4le4qpFlR7+P1
-3fLE2Y19IBwPwEfClC+TpJvuog6xqUYGPlg6XLq/MxQUB4ECQQDgovP1v+ONSeGS
-R+NgJTR47noTkQT3M2izlce/OG7a+O0yw6BOZjNXqH2wx3DshqMcPUFrTjibIClP
-l/tEQ3ShAkEA0/TdBYDtXpNNjqg0R9GVH2pw7Kh68ne6mZTuj0kCgFYpUF6L6iMm
-zXamIJ51rTDsTyKTAZ1JuAhAsK/M2BbDBQJAKQ5fXEkIA+i+64dsDUR/hKLBeRYG
-PFAPENONQGvGBwt7/s02XV3cgGbxIgAxqWkqIp0neb9AJUoJgtyaNe3GQQJANoL4
-QQ0af0NVJAZgg8QEHTNL3aGrFSbzx8IE5Lb7PLRsJa5bP5lQxnDoYuU+EI/Phr62
-niisp/b/ZDGidkTMXQJBALeRsH1I+LmICAvWXpLKa9Gv0zGCwkuIJLiUbV9c6CVh
-suocCAteQwL5iW2gA4AnYr5OGeHFsEl7NCQcwfPZpJ0=
------END RSA PRIVATE KEY-----
-EOD;
- }
-
- /** @dataProvider provideClientCredentials */
- public function testJwtUtil($client_id, $client_key)
- {
- $jwtUtil = new Jwt();
-
- $params = array(
- 'iss' => $client_id,
- 'exp' => time() + 1000,
- 'iat' => time(),
- 'sub' => 'testuser@ourdomain.com',
- 'aud' => 'http://myapp.com/oauth/auth',
- 'scope' => null,
- );
-
- $encoded = $jwtUtil->encode($params, $this->privateKey, 'RS256');
-
- // test BC behaviour of trusting the algorithm in the header
- $payload = $jwtUtil->decode($encoded, $client_key);
- $this->assertEquals($params, $payload);
-
- // test BC behaviour of not verifying by passing false
- $payload = $jwtUtil->decode($encoded, $client_key, false);
- $this->assertEquals($params, $payload);
-
- // test the new restricted algorithms header
- $payload = $jwtUtil->decode($encoded, $client_key, array('RS256'));
- $this->assertEquals($params, $payload);
- }
-
- public function testInvalidJwt()
- {
- $jwtUtil = new Jwt();
-
- $this->assertFalse($jwtUtil->decode('goob'));
- $this->assertFalse($jwtUtil->decode('go.o.b'));
- }
-
- /** @dataProvider provideClientCredentials */
- public function testInvalidJwtHeader($client_id, $client_key)
- {
- $jwtUtil = new Jwt();
-
- $params = array(
- 'iss' => $client_id,
- 'exp' => time() + 1000,
- 'iat' => time(),
- 'sub' => 'testuser@ourdomain.com',
- 'aud' => 'http://myapp.com/oauth/auth',
- 'scope' => null,
- );
-
- // testing for algorithm tampering when only RSA256 signing is allowed
- // @see https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
- $tampered = $jwtUtil->encode($params, $client_key, 'HS256');
-
- $payload = $jwtUtil->decode($tampered, $client_key, array('RS256'));
-
- $this->assertFalse($payload);
- }
-
- public function provideClientCredentials()
- {
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $client_id = 'Test Client ID';
- $client_key = $storage->getClientKey($client_id, "testuser@ourdomain.com");
-
- return array(
- array($client_id, $client_key),
- );
- }
-}
diff --git a/library/oauth2/test/OAuth2/GrantType/AuthorizationCodeTest.php b/library/oauth2/test/OAuth2/GrantType/AuthorizationCodeTest.php
deleted file mode 100644
index 740989635..000000000
--- a/library/oauth2/test/OAuth2/GrantType/AuthorizationCodeTest.php
+++ /dev/null
@@ -1,207 +0,0 @@
-<?php
-
-namespace OAuth2\GrantType;
-
-use OAuth2\Storage\Bootstrap;
-use OAuth2\Server;
-use OAuth2\Request\TestRequest;
-use OAuth2\Response;
-
-class AuthorizationCodeTest extends \PHPUnit_Framework_TestCase
-{
- public function testNoCode()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- ));
- $server->handleTokenRequest($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_request');
- $this->assertEquals($response->getParameter('error_description'), 'Missing parameter: "code" is required');
- }
-
- public function testInvalidCode()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'code' => 'InvalidCode', // invalid authorization code
- ));
- $server->handleTokenRequest($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'Authorization code doesn\'t exist or is invalid for the client');
- }
-
- public function testCodeCannotBeUsedTwice()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'code' => 'testcode', // valid code
- ));
- $server->handleTokenRequest($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 200);
- $this->assertNotNull($response->getParameter('access_token'));
-
- // try to use the same code again
- $server->handleTokenRequest($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'Authorization code doesn\'t exist or is invalid for the client');
- }
-
- public function testExpiredCode()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'code' => 'testcode-expired', // expired authorization code
- ));
- $server->handleTokenRequest($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'The authorization code has expired');
- }
-
- public function testValidCode()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'code' => 'testcode', // valid code
- ));
- $token = $server->grantAccessToken($request, new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- }
-
- public function testValidCodeNoScope()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'code' => 'testcode-with-scope', // valid code
- ));
- $token = $server->grantAccessToken($request, new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- $this->assertArrayHasKey('scope', $token);
- $this->assertEquals($token['scope'], 'scope1 scope2');
- }
-
- public function testValidCodeSameScope()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'code' => 'testcode-with-scope', // valid code
- 'scope' => 'scope2 scope1',
- ));
- $token = $server->grantAccessToken($request, new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- $this->assertArrayHasKey('scope', $token);
- $this->assertEquals($token['scope'], 'scope2 scope1');
- }
-
- public function testValidCodeLessScope()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'code' => 'testcode-with-scope', // valid code
- 'scope' => 'scope1',
- ));
- $token = $server->grantAccessToken($request, new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- $this->assertArrayHasKey('scope', $token);
- $this->assertEquals($token['scope'], 'scope1');
- }
-
- public function testValidCodeDifferentScope()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'code' => 'testcode-with-scope', // valid code
- 'scope' => 'scope3',
- ));
- $token = $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_scope');
- $this->assertEquals($response->getParameter('error_description'), 'The scope requested is invalid for this request');
- }
-
- public function testValidCodeInvalidScope()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'code' => 'testcode-with-scope', // valid code
- 'scope' => 'invalid-scope',
- ));
- $token = $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_scope');
- $this->assertEquals($response->getParameter('error_description'), 'The scope requested is invalid for this request');
- }
-
- public function testValidClientDifferentCode()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'client_id' => 'Test Some Other Client', // valid client id
- 'client_secret' => 'TestSecret3', // valid client secret
- 'code' => 'testcode', // valid code
- ));
- $token = $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'authorization_code doesn\'t exist or is invalid for the client');
- }
-
- private function getTestServer()
- {
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $server = new Server($storage);
- $server->addGrantType(new AuthorizationCode($storage));
-
- return $server;
- }
-}
diff --git a/library/oauth2/test/OAuth2/GrantType/ClientCredentialsTest.php b/library/oauth2/test/OAuth2/GrantType/ClientCredentialsTest.php
deleted file mode 100644
index f0d46ccb3..000000000
--- a/library/oauth2/test/OAuth2/GrantType/ClientCredentialsTest.php
+++ /dev/null
@@ -1,159 +0,0 @@
-<?php
-
-namespace OAuth2\GrantType;
-
-use OAuth2\Storage\Bootstrap;
-use OAuth2\Server;
-use OAuth2\Request\TestRequest;
-use OAuth2\Request;
-use OAuth2\Response;
-
-class ClientCredentialsTest extends \PHPUnit_Framework_TestCase
-{
- public function testInvalidCredentials()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'client_credentials', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'FakeSecret', // valid client secret
- ));
- $server->handleTokenRequest($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_client');
- $this->assertEquals($response->getParameter('error_description'), 'The client credentials are invalid');
- }
-
- public function testValidCredentials()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'client_credentials', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- ));
- $token = $server->grantAccessToken($request, new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('scope', $token);
- $this->assertNull($token['scope']);
- }
-
- public function testValidCredentialsWithScope()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'client_credentials', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'scope' => 'scope1',
- ));
- $token = $server->grantAccessToken($request, new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- $this->assertArrayHasKey('scope', $token);
- $this->assertEquals($token['scope'], 'scope1');
- }
-
- public function testValidCredentialsInvalidScope()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'client_credentials', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'scope' => 'invalid-scope',
- ));
- $token = $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_scope');
- $this->assertEquals($response->getParameter('error_description'), 'An unsupported scope was requested');
- }
-
- public function testValidCredentialsInHeader()
- {
- // create with HTTP_AUTHORIZATION in header
- $server = $this->getTestServer();
- $headers = array('HTTP_AUTHORIZATION' => 'Basic '.base64_encode('Test Client ID:TestSecret'), 'REQUEST_METHOD' => 'POST');
- $params = array('grant_type' => 'client_credentials');
- $request = new Request(array(), $params, array(), array(), array(), $headers);
- $token = $server->grantAccessToken($request, new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- $this->assertNotNull($token['access_token']);
-
- // create using PHP Authorization Globals
- $headers = array('PHP_AUTH_USER' => 'Test Client ID', 'PHP_AUTH_PW' => 'TestSecret', 'REQUEST_METHOD' => 'POST');
- $params = array('grant_type' => 'client_credentials');
- $request = new Request(array(), $params, array(), array(), array(), $headers);
- $token = $server->grantAccessToken($request, new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- $this->assertNotNull($token['access_token']);
- }
-
- public function testValidCredentialsInRequest()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'client_credentials', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- ));
- $token = $server->grantAccessToken($request, new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- $this->assertNotNull($token['access_token']);
- }
-
- public function testValidCredentialsInQuerystring()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'client_credentials', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- ));
- $token = $server->grantAccessToken($request, new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- $this->assertNotNull($token['access_token']);
- }
-
- public function testClientUserIdIsSetInAccessToken()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'client_credentials', // valid grant type
- 'client_id' => 'Client ID With User ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- ));
- $token = $server->grantAccessToken($request, new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
-
- // verify the user_id was associated with the token
- $storage = $server->getStorage('client');
- $token = $storage->getAccessToken($token['access_token']);
- $this->assertNotNull($token);
- $this->assertArrayHasKey('user_id', $token);
- $this->assertEquals($token['user_id'], 'brent@brentertainment.com');
- }
-
- private function getTestServer()
- {
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $server = new Server($storage);
- $server->addGrantType(new ClientCredentials($storage));
-
- return $server;
- }
-}
diff --git a/library/oauth2/test/OAuth2/GrantType/ImplicitTest.php b/library/oauth2/test/OAuth2/GrantType/ImplicitTest.php
deleted file mode 100644
index a47aae3e8..000000000
--- a/library/oauth2/test/OAuth2/GrantType/ImplicitTest.php
+++ /dev/null
@@ -1,143 +0,0 @@
-<?php
-
-namespace OAuth2\GrantType;
-
-use OAuth2\Storage\Bootstrap;
-use OAuth2\Server;
-use OAuth2\Request;
-use OAuth2\Response;
-
-class ImplicitTest extends \PHPUnit_Framework_TestCase
-{
- public function testImplicitNotAllowedResponse()
- {
- $server = $this->getTestServer();
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- 'redirect_uri' => 'http://adobe.com', // valid redirect URI
- 'response_type' => 'token', // invalid response type
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), false);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $location = $response->getHttpHeader('Location');
- $parts = parse_url($location);
- parse_str($parts['query'], $query);
-
- $this->assertEquals($query['error'], 'unsupported_response_type');
- $this->assertEquals($query['error_description'], 'implicit grant type not supported');
- }
-
- public function testUserDeniesAccessResponse()
- {
- $server = $this->getTestServer(array('allow_implicit' => true));
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- 'redirect_uri' => 'http://adobe.com', // valid redirect URI
- 'response_type' => 'token', // valid response type
- 'state' => 'xyz',
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), false);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $location = $response->getHttpHeader('Location');
- $parts = parse_url($location);
- parse_str($parts['query'], $query);
-
- $this->assertEquals($query['error'], 'access_denied');
- $this->assertEquals($query['error_description'], 'The user denied access to your application');
- }
-
- public function testSuccessfulRequestFragmentParameter()
- {
- $server = $this->getTestServer(array('allow_implicit' => true));
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- 'redirect_uri' => 'http://adobe.com', // valid redirect URI
- 'response_type' => 'token', // valid response type
- 'state' => 'xyz',
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $this->assertNull($response->getParameter('error'));
- $this->assertNull($response->getParameter('error_description'));
-
- $location = $response->getHttpHeader('Location');
- $parts = parse_url($location);
-
- $this->assertEquals('http', $parts['scheme']); // same as passed in to redirect_uri
- $this->assertEquals('adobe.com', $parts['host']); // same as passed in to redirect_uri
- $this->assertArrayHasKey('fragment', $parts);
- $this->assertFalse(isset($parts['query']));
-
- // assert fragment is in "application/x-www-form-urlencoded" format
- parse_str($parts['fragment'], $params);
- $this->assertNotNull($params);
- $this->assertArrayHasKey('access_token', $params);
- $this->assertArrayHasKey('expires_in', $params);
- $this->assertArrayHasKey('token_type', $params);
- }
-
- public function testSuccessfulRequestReturnsStateParameter()
- {
- $server = $this->getTestServer(array('allow_implicit' => true));
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- 'redirect_uri' => 'http://adobe.com', // valid redirect URI
- 'response_type' => 'token', // valid response type
- 'state' => 'test', // valid state string (just needs to be passed back to us)
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $this->assertNull($response->getParameter('error'));
- $this->assertNull($response->getParameter('error_description'));
-
- $location = $response->getHttpHeader('Location');
- $parts = parse_url($location);
- $this->assertArrayHasKey('fragment', $parts);
- parse_str($parts['fragment'], $params);
-
- $this->assertArrayHasKey('state', $params);
- $this->assertEquals($params['state'], 'test');
- }
-
- public function testSuccessfulRequestStripsExtraParameters()
- {
- $server = $this->getTestServer(array('allow_implicit' => true));
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- 'redirect_uri' => 'http://adobe.com?fake=something', // valid redirect URI
- 'response_type' => 'token', // valid response type
- 'state' => 'test', // valid state string (just needs to be passed back to us)
- 'fake' => 'something', // add extra param to querystring
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $this->assertNull($response->getParameter('error'));
- $this->assertNull($response->getParameter('error_description'));
-
- $location = $response->getHttpHeader('Location');
- $parts = parse_url($location);
- $this->assertFalse(isset($parts['fake']));
- $this->assertArrayHasKey('fragment', $parts);
- parse_str($parts['fragment'], $params);
-
- $this->assertFalse(isset($params['fake']));
- $this->assertArrayHasKey('state', $params);
- $this->assertEquals($params['state'], 'test');
- }
-
- private function getTestServer($config = array())
- {
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $server = new Server($storage, $config);
-
- // Add the two types supported for authorization grant
- $server->addGrantType(new AuthorizationCode($storage));
-
- return $server;
- }
-}
diff --git a/library/oauth2/test/OAuth2/GrantType/JwtBearerTest.php b/library/oauth2/test/OAuth2/GrantType/JwtBearerTest.php
deleted file mode 100644
index 0a6c4b827..000000000
--- a/library/oauth2/test/OAuth2/GrantType/JwtBearerTest.php
+++ /dev/null
@@ -1,360 +0,0 @@
-<?php
-
-namespace OAuth2\GrantType;
-
-use OAuth2\Storage\Bootstrap;
-use OAuth2\Server;
-use OAuth2\Request\TestRequest;
-use OAuth2\Response;
-use OAuth2\Encryption\Jwt;
-
-class JwtBearerTest extends \PHPUnit_Framework_TestCase
-{
- private $privateKey;
-
- public function setUp()
- {
- $this->privateKey = <<<EOD
------BEGIN RSA PRIVATE KEY-----
-MIICXAIBAAKBgQC5/SxVlE8gnpFqCxgl2wjhzY7ucEi00s0kUg3xp7lVEvgLgYcA
-nHiWp+gtSjOFfH2zsvpiWm6Lz5f743j/FEzHIO1owR0p4d9pOaJK07d01+RzoQLO
-IQAgXrr4T1CCWUesncwwPBVCyy2Mw3Nmhmr9MrF8UlvdRKBxriRnlP3qJQIDAQAB
-AoGAVgJJVU4fhYMu1e5JfYAcTGfF+Gf+h3iQm4JCpoUcxMXf5VpB9ztk3K7LRN5y
-kwFuFALpnUAarRcUPs0D8FoP4qBluKksbAtgHkO7bMSH9emN+mH4le4qpFlR7+P1
-3fLE2Y19IBwPwEfClC+TpJvuog6xqUYGPlg6XLq/MxQUB4ECQQDgovP1v+ONSeGS
-R+NgJTR47noTkQT3M2izlce/OG7a+O0yw6BOZjNXqH2wx3DshqMcPUFrTjibIClP
-l/tEQ3ShAkEA0/TdBYDtXpNNjqg0R9GVH2pw7Kh68ne6mZTuj0kCgFYpUF6L6iMm
-zXamIJ51rTDsTyKTAZ1JuAhAsK/M2BbDBQJAKQ5fXEkIA+i+64dsDUR/hKLBeRYG
-PFAPENONQGvGBwt7/s02XV3cgGbxIgAxqWkqIp0neb9AJUoJgtyaNe3GQQJANoL4
-QQ0af0NVJAZgg8QEHTNL3aGrFSbzx8IE5Lb7PLRsJa5bP5lQxnDoYuU+EI/Phr62
-niisp/b/ZDGidkTMXQJBALeRsH1I+LmICAvWXpLKa9Gv0zGCwkuIJLiUbV9c6CVh
-suocCAteQwL5iW2gA4AnYr5OGeHFsEl7NCQcwfPZpJ0=
------END RSA PRIVATE KEY-----
-EOD;
- }
-
- public function testMalformedJWT()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type
- ));
-
- //Get the jwt and break it
- $jwt = $this->getJWT();
- $jwt = substr_replace($jwt, 'broken', 3, 6);
-
- $request->request['assertion'] = $jwt;
-
- $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_request');
- $this->assertEquals($response->getParameter('error_description'), 'JWT is malformed');
- }
-
- public function testBrokenSignature()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type
- ));
-
- //Get the jwt and break signature
- $jwt = $this->getJWT() . 'notSupposeToBeHere';
- $request->request['assertion'] = $jwt;
-
- $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'JWT failed signature verification');
- }
-
- public function testExpiredJWT()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type
- ));
-
- //Get an expired JWT
- $jwt = $this->getJWT(1234);
- $request->request['assertion'] = $jwt;
-
- $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'JWT has expired');
- }
-
- public function testBadExp()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type
- ));
-
- //Get an expired JWT
- $jwt = $this->getJWT('badtimestamp');
- $request->request['assertion'] = $jwt;
-
- $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'Expiration (exp) time must be a unix time stamp');
- }
-
- public function testNoAssert()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type
- ));
-
- //Do not pass the assert (JWT)
-
- $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_request');
- $this->assertEquals($response->getParameter('error_description'), 'Missing parameters: "assertion" required');
- }
-
- public function testNotBefore()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type
- ));
-
- //Get a future NBF
- $jwt = $this->getJWT(null, time() + 10000);
- $request->request['assertion'] = $jwt;
-
- $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'JWT cannot be used before the Not Before (nbf) time');
- }
-
- public function testBadNotBefore()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type
- ));
-
- //Get a non timestamp nbf
- $jwt = $this->getJWT(null, 'notatimestamp');
- $request->request['assertion'] = $jwt;
-
- $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'Not Before (nbf) time must be a unix time stamp');
- }
-
- public function testNonMatchingAudience()
- {
- $server = $this->getTestServer('http://google.com/oauth/o/auth');
- $request = TestRequest::createPost(array(
- 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type
- 'assertion' => $this->getJWT(),
- ));
-
- $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'Invalid audience (aud)');
- }
-
- public function testBadClientID()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type
- 'assertion' => $this->getJWT(null, null, null, 'bad_client_id'),
- ));
-
- $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'Invalid issuer (iss) or subject (sub) provided');
- }
-
- public function testBadSubject()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type
- 'assertion' => $this->getJWT(null, null, 'anotheruser@ourdomain,com'),
- ));
-
- $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'Invalid issuer (iss) or subject (sub) provided');
- }
-
- public function testMissingKey()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type
- 'assertion' => $this->getJWT(null, null, null, 'Missing Key Cli,nt'),
- ));
-
- $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'Invalid issuer (iss) or subject (sub) provided');
- }
-
- public function testValidJwt()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type
- 'assertion' => $this->getJWT(), // valid assertion
- ));
-
- $token = $server->grantAccessToken($request, new Response());
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- }
-
- public function testValidJwtWithScope()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type
- 'assertion' => $this->getJWT(null, null, null, 'Test Client ID'), // valid assertion
- 'scope' => 'scope1', // valid scope
- ));
- $token = $server->grantAccessToken($request, new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- $this->assertArrayHasKey('scope', $token);
- $this->assertEquals($token['scope'], 'scope1');
- }
-
- public function testValidJwtInvalidScope()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type
- 'assertion' => $this->getJWT(null, null, null, 'Test Client ID'), // valid assertion
- 'scope' => 'invalid-scope', // invalid scope
- ));
- $token = $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_scope');
- $this->assertEquals($response->getParameter('error_description'), 'An unsupported scope was requested');
- }
-
- public function testValidJti()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type
- 'assertion' => $this->getJWT(null, null, 'testuser@ourdomain.com', 'Test Client ID', 'unused_jti'), // valid assertion with invalid scope
- ));
- $token = $server->grantAccessToken($request, $response = new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- }
-
- public function testInvalidJti()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type
- 'assertion' => $this->getJWT(99999999900, null, 'testuser@ourdomain.com', 'Test Client ID', 'used_jti'), // valid assertion with invalid scope
- ));
- $token = $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'JSON Token Identifier (jti) has already been used');
- }
-
- public function testJtiReplayAttack()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type
- 'assertion' => $this->getJWT(99999999900, null, 'testuser@ourdomain.com', 'Test Client ID', 'totally_new_jti'), // valid assertion with invalid scope
- ));
- $token = $server->grantAccessToken($request, $response = new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
-
- //Replay the same request
- $token = $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'JSON Token Identifier (jti) has already been used');
- }
-
- /**
- * Generates a JWT
- * @param $exp The expiration date. If the current time is greater than the exp, the JWT is invalid.
- * @param $nbf The "not before" time. If the current time is less than the nbf, the JWT is invalid.
- * @param $sub The subject we are acting on behalf of. This could be the email address of the user in the system.
- * @param $iss The issuer, usually the client_id.
- * @return string
- */
- private function getJWT($exp = null, $nbf = null, $sub = null, $iss = 'Test Client ID', $jti = null)
- {
- if (!$exp) {
- $exp = time() + 1000;
- }
-
- if (!$sub) {
- $sub = "testuser@ourdomain.com";
- }
-
- $params = array(
- 'iss' => $iss,
- 'exp' => $exp,
- 'iat' => time(),
- 'sub' => $sub,
- 'aud' => 'http://myapp.com/oauth/auth',
- );
-
- if ($nbf) {
- $params['nbf'] = $nbf;
- }
-
- if ($jti) {
- $params['jti'] = $jti;
- }
-
- $jwtUtil = new Jwt();
-
- return $jwtUtil->encode($params, $this->privateKey, 'RS256');
- }
-
- private function getTestServer($audience = 'http://myapp.com/oauth/auth')
- {
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $server = new Server($storage);
- $server->addGrantType(new JwtBearer($storage, $audience, new Jwt()));
-
- return $server;
- }
-}
diff --git a/library/oauth2/test/OAuth2/GrantType/RefreshTokenTest.php b/library/oauth2/test/OAuth2/GrantType/RefreshTokenTest.php
deleted file mode 100644
index a458aad8a..000000000
--- a/library/oauth2/test/OAuth2/GrantType/RefreshTokenTest.php
+++ /dev/null
@@ -1,204 +0,0 @@
-<?php
-
-namespace OAuth2\GrantType;
-
-use OAuth2\Storage\Bootstrap;
-use OAuth2\Server;
-use OAuth2\Request\TestRequest;
-use OAuth2\Response;
-
-class RefreshTokenTest extends \PHPUnit_Framework_TestCase
-{
- private $storage;
-
- public function testNoRefreshToken()
- {
- $server = $this->getTestServer();
- $server->addGrantType(new RefreshToken($this->storage));
-
- $request = TestRequest::createPost(array(
- 'grant_type' => 'refresh_token', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- ));
- $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_request');
- $this->assertEquals($response->getParameter('error_description'), 'Missing parameter: "refresh_token" is required');
- }
-
- public function testInvalidRefreshToken()
- {
- $server = $this->getTestServer();
- $server->addGrantType(new RefreshToken($this->storage));
-
- $request = TestRequest::createPost(array(
- 'grant_type' => 'refresh_token', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'refresh_token' => 'fake-token', // invalid refresh token
- ));
- $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'Invalid refresh token');
- }
-
- public function testValidRefreshTokenWithNewRefreshTokenInResponse()
- {
- $server = $this->getTestServer();
- $server->addGrantType(new RefreshToken($this->storage, array('always_issue_new_refresh_token' => true)));
-
- $request = TestRequest::createPost(array(
- 'grant_type' => 'refresh_token', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'refresh_token' => 'test-refreshtoken', // valid refresh token
- ));
- $token = $server->grantAccessToken($request, new Response());
- $this->assertTrue(isset($token['refresh_token']), 'refresh token should always refresh');
-
- $refresh_token = $this->storage->getRefreshToken($token['refresh_token']);
- $this->assertNotNull($refresh_token);
- $this->assertEquals($refresh_token['refresh_token'], $token['refresh_token']);
- $this->assertEquals($refresh_token['client_id'], $request->request('client_id'));
- $this->assertTrue($token['refresh_token'] != 'test-refreshtoken', 'the refresh token returned is not the one used');
- $used_token = $this->storage->getRefreshToken('test-refreshtoken');
- $this->assertFalse($used_token, 'the refresh token used is no longer valid');
- }
-
- public function testValidRefreshTokenDoesNotUnsetToken()
- {
- $server = $this->getTestServer();
- $server->addGrantType(new RefreshToken($this->storage, array(
- 'always_issue_new_refresh_token' => true,
- 'unset_refresh_token_after_use' => false,
- )));
-
- $request = TestRequest::createPost(array(
- 'grant_type' => 'refresh_token', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'refresh_token' => 'test-refreshtoken', // valid refresh token
- ));
- $token = $server->grantAccessToken($request, new Response());
- $this->assertTrue(isset($token['refresh_token']), 'refresh token should always refresh');
-
- $used_token = $this->storage->getRefreshToken('test-refreshtoken');
- $this->assertNotNull($used_token, 'the refresh token used is still valid');
- }
-
- public function testValidRefreshTokenWithNoRefreshTokenInResponse()
- {
- $server = $this->getTestServer();
- $server->addGrantType(new RefreshToken($this->storage, array('always_issue_new_refresh_token' => false)));
-
- $request = TestRequest::createPost(array(
- 'grant_type' => 'refresh_token', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'refresh_token' => 'test-refreshtoken', // valid refresh token
- ));
- $token = $server->grantAccessToken($request, new Response());
- $this->assertFalse(isset($token['refresh_token']), 'refresh token should not be returned');
-
- $used_token = $this->storage->getRefreshToken('test-refreshtoken');
- $this->assertNotNull($used_token, 'the refresh token used is still valid');
- }
-
- public function testValidRefreshTokenSameScope()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'refresh_token', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'refresh_token' => 'test-refreshtoken-with-scope', // valid refresh token (with scope)
- 'scope' => 'scope2 scope1',
- ));
- $token = $server->grantAccessToken($request, new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- $this->assertArrayHasKey('scope', $token);
- $this->assertEquals($token['scope'], 'scope2 scope1');
- }
-
- public function testValidRefreshTokenLessScope()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'refresh_token', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'refresh_token' => 'test-refreshtoken-with-scope', // valid refresh token (with scope)
- 'scope' => 'scope1',
- ));
- $token = $server->grantAccessToken($request, new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- $this->assertArrayHasKey('scope', $token);
- $this->assertEquals($token['scope'], 'scope1');
- }
-
- public function testValidRefreshTokenDifferentScope()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'refresh_token', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'refresh_token' => 'test-refreshtoken-with-scope', // valid refresh token (with scope)
- 'scope' => 'scope3',
- ));
- $token = $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_scope');
- $this->assertEquals($response->getParameter('error_description'), 'The scope requested is invalid for this request');
- }
-
- public function testValidRefreshTokenInvalidScope()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'refresh_token', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'refresh_token' => 'test-refreshtoken-with-scope', // valid refresh token (with scope)
- 'scope' => 'invalid-scope',
- ));
- $token = $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_scope');
- $this->assertEquals($response->getParameter('error_description'), 'The scope requested is invalid for this request');
- }
-
- public function testValidClientDifferentRefreshToken()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'refresh_token', // valid grant type
- 'client_id' => 'Test Some Other Client', // valid client id
- 'client_secret' => 'TestSecret3', // valid client secret
- 'refresh_token' => 'test-refreshtoken', // valid refresh token
- ));
- $token = $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'refresh_token doesn\'t exist or is invalid for the client');
- }
-
- private function getTestServer()
- {
- $this->storage = Bootstrap::getInstance()->getMemoryStorage();
- $server = new Server($this->storage);
-
- return $server;
- }
-}
diff --git a/library/oauth2/test/OAuth2/GrantType/UserCredentialsTest.php b/library/oauth2/test/OAuth2/GrantType/UserCredentialsTest.php
deleted file mode 100644
index 18943d055..000000000
--- a/library/oauth2/test/OAuth2/GrantType/UserCredentialsTest.php
+++ /dev/null
@@ -1,172 +0,0 @@
-<?php
-
-namespace OAuth2\GrantType;
-
-use OAuth2\Storage\Bootstrap;
-use OAuth2\Server;
-use OAuth2\Request\TestRequest;
-use OAuth2\Response;
-
-class UserCredentialsTest extends \PHPUnit_Framework_TestCase
-{
- public function testNoUsername()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'password', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'password' => 'testpass', // valid password
- ));
- $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_request');
- $this->assertEquals($response->getParameter('error_description'), 'Missing parameters: "username" and "password" required');
- }
-
- public function testNoPassword()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'password', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'username' => 'test-username', // valid username
- ));
- $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_request');
- $this->assertEquals($response->getParameter('error_description'), 'Missing parameters: "username" and "password" required');
- }
-
- public function testInvalidUsername()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'password', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'username' => 'fake-username', // valid username
- 'password' => 'testpass', // valid password
- ));
- $token = $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 401);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'Invalid username and password combination');
- }
-
- public function testInvalidPassword()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'password', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'username' => 'test-username', // valid username
- 'password' => 'fakepass', // invalid password
- ));
- $token = $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 401);
- $this->assertEquals($response->getParameter('error'), 'invalid_grant');
- $this->assertEquals($response->getParameter('error_description'), 'Invalid username and password combination');
- }
-
- public function testValidCredentials()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'password', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'username' => 'test-username', // valid username
- 'password' => 'testpass', // valid password
- ));
- $token = $server->grantAccessToken($request, new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- }
-
- public function testValidCredentialsWithScope()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'password', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'username' => 'test-username', // valid username
- 'password' => 'testpass', // valid password
- 'scope' => 'scope1', // valid scope
- ));
- $token = $server->grantAccessToken($request, new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- $this->assertArrayHasKey('scope', $token);
- $this->assertEquals($token['scope'], 'scope1');
- }
-
- public function testValidCredentialsInvalidScope()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'password', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'username' => 'test-username', // valid username
- 'password' => 'testpass', // valid password
- 'scope' => 'invalid-scope',
- ));
- $token = $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_scope');
- $this->assertEquals($response->getParameter('error_description'), 'An unsupported scope was requested');
- }
-
- public function testNoSecretWithPublicClient()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'password', // valid grant type
- 'client_id' => 'Test Client ID Empty Secret', // valid public client
- 'username' => 'test-username', // valid username
- 'password' => 'testpass', // valid password
- ));
-
- $token = $server->grantAccessToken($request, $response = new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- }
-
- public function testNoSecretWithConfidentialClient()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'password', // valid grant type
- 'client_id' => 'Test Client ID', // valid public client
- 'username' => 'test-username', // valid username
- 'password' => 'testpass', // valid password
- ));
-
- $token = $server->grantAccessToken($request, $response = new Response());
-
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_client');
- $this->assertEquals($response->getParameter('error_description'), 'This client is invalid or must authenticate using a client secret');
- }
-
- private function getTestServer()
- {
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $server = new Server($storage);
- $server->addGrantType(new UserCredentials($storage));
-
- return $server;
- }
-}
diff --git a/library/oauth2/test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php b/library/oauth2/test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php
deleted file mode 100644
index 46de936d8..000000000
--- a/library/oauth2/test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php
+++ /dev/null
@@ -1,182 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\Controller;
-
-use OAuth2\Storage\Bootstrap;
-use OAuth2\Server;
-use OAuth2\Request;
-use OAuth2\Response;
-
-class AuthorizeControllerTest extends \PHPUnit_Framework_TestCase
-{
- public function testValidateAuthorizeRequest()
- {
- $server = $this->getTestServer();
-
- $response = new Response();
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- 'redirect_uri' => 'http://adobe.com', // valid redirect URI
- 'response_type' => 'id_token',
- 'state' => 'af0ifjsldkj',
- 'nonce' => 'n-0S6_WzA2Mj',
- ));
-
- // Test valid id_token request
- $server->handleAuthorizeRequest($request, $response, true);
-
- $parts = parse_url($response->getHttpHeader('Location'));
- parse_str($parts['fragment'], $query);
-
- $this->assertEquals('n-0S6_WzA2Mj', $server->getAuthorizeController()->getNonce());
- $this->assertEquals($query['state'], 'af0ifjsldkj');
-
- $this->assertArrayHasKey('id_token', $query);
- $this->assertArrayHasKey('state', $query);
- $this->assertArrayNotHasKey('access_token', $query);
- $this->assertArrayNotHasKey('expires_in', $query);
- $this->assertArrayNotHasKey('token_type', $query);
-
- // Test valid token id_token request
- $request->query['response_type'] = 'id_token token';
- $server->handleAuthorizeRequest($request, $response, true);
-
- $parts = parse_url($response->getHttpHeader('Location'));
- parse_str($parts['fragment'], $query);
-
- $this->assertEquals('n-0S6_WzA2Mj', $server->getAuthorizeController()->getNonce());
- $this->assertEquals($query['state'], 'af0ifjsldkj');
-
- $this->assertArrayHasKey('access_token', $query);
- $this->assertArrayHasKey('expires_in', $query);
- $this->assertArrayHasKey('token_type', $query);
- $this->assertArrayHasKey('state', $query);
- $this->assertArrayHasKey('id_token', $query);
-
- // assert that with multiple-valued response types, order does not matter
- $request->query['response_type'] = 'token id_token';
- $server->handleAuthorizeRequest($request, $response, true);
-
- $parts = parse_url($response->getHttpHeader('Location'));
- parse_str($parts['fragment'], $query);
-
- $this->assertEquals('n-0S6_WzA2Mj', $server->getAuthorizeController()->getNonce());
- $this->assertEquals($query['state'], 'af0ifjsldkj');
-
- $this->assertArrayHasKey('access_token', $query);
- $this->assertArrayHasKey('expires_in', $query);
- $this->assertArrayHasKey('token_type', $query);
- $this->assertArrayHasKey('state', $query);
- $this->assertArrayHasKey('id_token', $query);
-
- // assert that with multiple-valued response types with extra spaces do not matter
- $request->query['response_type'] = ' token id_token ';
- $server->handleAuthorizeRequest($request, $response, true);
-
- $parts = parse_url($response->getHttpHeader('Location'));
- parse_str($parts['fragment'], $query);
-
- $this->assertEquals('n-0S6_WzA2Mj', $server->getAuthorizeController()->getNonce());
- $this->assertEquals($query['state'], 'af0ifjsldkj');
-
- $this->assertArrayHasKey('access_token', $query);
- $this->assertArrayHasKey('expires_in', $query);
- $this->assertArrayHasKey('token_type', $query);
- $this->assertArrayHasKey('state', $query);
- $this->assertArrayHasKey('id_token', $query);
- }
-
- public function testMissingNonce()
- {
- $server = $this->getTestServer();
- $authorize = $server->getAuthorizeController();
-
- $response = new Response();
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- 'redirect_uri' => 'http://adobe.com', // valid redirect URI
- 'response_type' => 'id_token',
- 'state' => 'xyz',
- ));
-
- // Test missing nonce for 'id_token' response type
- $server->handleAuthorizeRequest($request, $response, true);
- $params = $response->getParameters();
-
- $this->assertEquals($params['error'], 'invalid_nonce');
- $this->assertEquals($params['error_description'], 'This application requires you specify a nonce parameter');
-
- // Test missing nonce for 'id_token token' response type
- $request->query['response_type'] = 'id_token token';
- $server->handleAuthorizeRequest($request, $response, true);
- $params = $response->getParameters();
-
- $this->assertEquals($params['error'], 'invalid_nonce');
- $this->assertEquals($params['error_description'], 'This application requires you specify a nonce parameter');
- }
-
- public function testNotGrantedApplication()
- {
- $server = $this->getTestServer();
-
- $response = new Response();
- $request = new Request(array(
- 'client_id' => 'Test Client ID', // valid client id
- 'redirect_uri' => 'http://adobe.com', // valid redirect URI
- 'response_type' => 'id_token',
- 'state' => 'af0ifjsldkj',
- 'nonce' => 'n-0S6_WzA2Mj',
- ));
-
- // Test not approved application
- $server->handleAuthorizeRequest($request, $response, false);
-
- $params = $response->getParameters();
-
- $this->assertEquals($params['error'], 'consent_required');
- $this->assertEquals($params['error_description'], 'The user denied access to your application');
-
- // Test not approved application with prompt parameter
- $request->query['prompt'] = 'none';
- $server->handleAuthorizeRequest($request, $response, false);
-
- $params = $response->getParameters();
-
- $this->assertEquals($params['error'], 'login_required');
- $this->assertEquals($params['error_description'], 'The user must log in');
-
- // Test not approved application with user_id set
- $request->query['prompt'] = 'none';
- $server->handleAuthorizeRequest($request, $response, false, 'some-user-id');
-
- $params = $response->getParameters();
-
- $this->assertEquals($params['error'], 'interaction_required');
- $this->assertEquals($params['error_description'], 'The user must grant access to your application');
- }
-
- public function testNeedsIdToken()
- {
- $server = $this->getTestServer();
- $authorize = $server->getAuthorizeController();
-
- $this->assertTrue($authorize->needsIdToken('openid'));
- $this->assertTrue($authorize->needsIdToken('openid profile'));
- $this->assertFalse($authorize->needsIdToken(''));
- $this->assertFalse($authorize->needsIdToken('some-scope'));
- }
-
- private function getTestServer($config = array())
- {
- $config += array(
- 'use_openid_connect' => true,
- 'issuer' => 'phpunit',
- 'allow_implicit' => true
- );
-
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $server = new Server($storage, $config);
-
- return $server;
- }
-}
diff --git a/library/oauth2/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php b/library/oauth2/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php
deleted file mode 100644
index b1b687077..000000000
--- a/library/oauth2/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\Controller;
-
-use OAuth2\Storage\Bootstrap;
-use OAuth2\Server;
-use OAuth2\Request;
-use OAuth2\Response;
-
-class UserInfoControllerTest extends \PHPUnit_Framework_TestCase
-{
- public function testCreateController()
- {
- $tokenType = new \OAuth2\TokenType\Bearer();
- $storage = new \OAuth2\Storage\Memory();
- $controller = new UserInfoController($tokenType, $storage, $storage);
-
- $response = new Response();
- $controller->handleUserInfoRequest(new Request(), $response);
- $this->assertEquals(401, $response->getStatusCode());
- }
-
- public function testValidToken()
- {
- $server = $this->getTestServer();
- $request = Request::createFromGlobals();
- $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-openid-connect';
- $response = new Response();
-
- $server->handleUserInfoRequest($request, $response);
- $parameters = $response->getParameters();
- $this->assertEquals($parameters['sub'], 'testuser');
- $this->assertEquals($parameters['email'], 'testuser@test.com');
- $this->assertEquals($parameters['email_verified'], true);
- }
-
- private function getTestServer($config = array())
- {
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $server = new Server($storage, $config);
-
- return $server;
- }
-}
diff --git a/library/oauth2/test/OAuth2/OpenID/GrantType/AuthorizationCodeTest.php b/library/oauth2/test/OAuth2/OpenID/GrantType/AuthorizationCodeTest.php
deleted file mode 100644
index 776002d1e..000000000
--- a/library/oauth2/test/OAuth2/OpenID/GrantType/AuthorizationCodeTest.php
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\GrantType;
-
-use OAuth2\Storage\Bootstrap;
-use OAuth2\Server;
-use OAuth2\Request\TestRequest;
-use OAuth2\Response;
-
-class AuthorizationCodeTest extends \PHPUnit_Framework_TestCase
-{
- public function testValidCode()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'code' => 'testcode-openid', // valid code
- ));
- $token = $server->grantAccessToken($request, new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('id_token', $token);
- $this->assertEquals('test_id_token', $token['id_token']);
-
- // this is only true if "offline_access" was requested
- $this->assertFalse(isset($token['refresh_token']));
- }
-
- public function testOfflineAccess()
- {
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'code' => 'testcode-openid', // valid code
- 'scope' => 'offline_access', // valid code
- ));
- $token = $server->grantAccessToken($request, new Response());
-
- $this->assertNotNull($token);
- $this->assertArrayHasKey('id_token', $token);
- $this->assertEquals('test_id_token', $token['id_token']);
- $this->assertTrue(isset($token['refresh_token']));
- }
-
- private function getTestServer()
- {
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $server = new Server($storage, array('use_openid_connect' => true));
- $server->addGrantType(new AuthorizationCode($storage));
-
- return $server;
- }
-}
diff --git a/library/oauth2/test/OAuth2/OpenID/ResponseType/CodeIdTokenTest.php b/library/oauth2/test/OAuth2/OpenID/ResponseType/CodeIdTokenTest.php
deleted file mode 100644
index b0311434a..000000000
--- a/library/oauth2/test/OAuth2/OpenID/ResponseType/CodeIdTokenTest.php
+++ /dev/null
@@ -1,182 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\ResponseType;
-
-use OAuth2\Server;
-use OAuth2\Request;
-use OAuth2\Response;
-use OAuth2\Storage\Bootstrap;
-use OAuth2\GrantType\ClientCredentials;
-
-class CodeIdTokenTest extends \PHPUnit_Framework_TestCase
-{
- public function testHandleAuthorizeRequest()
- {
- // add the test parameters in memory
- $server = $this->getTestServer();
-
- $request = new Request(array(
- 'response_type' => 'code id_token',
- 'redirect_uri' => 'http://adobe.com',
- 'client_id' => 'Test Client ID',
- 'scope' => 'openid',
- 'state' => 'test',
- 'nonce' => 'test',
- ));
-
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $location = $response->getHttpHeader('Location');
- $this->assertNotContains('error', $location);
-
- $parts = parse_url($location);
- $this->assertArrayHasKey('query', $parts);
-
- // assert fragment is in "application/x-www-form-urlencoded" format
- parse_str($parts['query'], $params);
- $this->assertNotNull($params);
- $this->assertArrayHasKey('id_token', $params);
- $this->assertArrayHasKey('code', $params);
-
- // validate ID Token
- $parts = explode('.', $params['id_token']);
- foreach ($parts as &$part) {
- // Each part is a base64url encoded json string.
- $part = str_replace(array('-', '_'), array('+', '/'), $part);
- $part = base64_decode($part);
- $part = json_decode($part, true);
- }
- list($header, $claims, $signature) = $parts;
-
- $this->assertArrayHasKey('iss', $claims);
- $this->assertArrayHasKey('sub', $claims);
- $this->assertArrayHasKey('aud', $claims);
- $this->assertArrayHasKey('iat', $claims);
- $this->assertArrayHasKey('exp', $claims);
- $this->assertArrayHasKey('auth_time', $claims);
- $this->assertArrayHasKey('nonce', $claims);
-
- // only exists if an access token was granted along with the id_token
- $this->assertArrayNotHasKey('at_hash', $claims);
-
- $this->assertEquals($claims['iss'], 'test');
- $this->assertEquals($claims['aud'], 'Test Client ID');
- $this->assertEquals($claims['nonce'], 'test');
- $duration = $claims['exp'] - $claims['iat'];
- $this->assertEquals($duration, 3600);
- }
-
- public function testUserClaimsWithUserId()
- {
- // add the test parameters in memory
- $server = $this->getTestServer();
-
- $request = new Request(array(
- 'response_type' => 'code id_token',
- 'redirect_uri' => 'http://adobe.com',
- 'client_id' => 'Test Client ID',
- 'scope' => 'openid email',
- 'state' => 'test',
- 'nonce' => 'test',
- ));
-
- $userId = 'testuser';
- $server->handleAuthorizeRequest($request, $response = new Response(), true, $userId);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $location = $response->getHttpHeader('Location');
- $this->assertNotContains('error', $location);
-
- $parts = parse_url($location);
- $this->assertArrayHasKey('query', $parts);
-
- // assert fragment is in "application/x-www-form-urlencoded" format
- parse_str($parts['query'], $params);
- $this->assertNotNull($params);
- $this->assertArrayHasKey('id_token', $params);
- $this->assertArrayHasKey('code', $params);
-
- // validate ID Token
- $parts = explode('.', $params['id_token']);
- foreach ($parts as &$part) {
- // Each part is a base64url encoded json string.
- $part = str_replace(array('-', '_'), array('+', '/'), $part);
- $part = base64_decode($part);
- $part = json_decode($part, true);
- }
- list($header, $claims, $signature) = $parts;
-
- $this->assertArrayHasKey('email', $claims);
- $this->assertArrayHasKey('email_verified', $claims);
- $this->assertNotNull($claims['email']);
- $this->assertNotNull($claims['email_verified']);
- }
-
- public function testUserClaimsWithoutUserId()
- {
- // add the test parameters in memory
- $server = $this->getTestServer();
-
- $request = new Request(array(
- 'response_type' => 'code id_token',
- 'redirect_uri' => 'http://adobe.com',
- 'client_id' => 'Test Client ID',
- 'scope' => 'openid email',
- 'state' => 'test',
- 'nonce' => 'test',
- ));
-
- $userId = null;
- $server->handleAuthorizeRequest($request, $response = new Response(), true, $userId);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $location = $response->getHttpHeader('Location');
- $this->assertNotContains('error', $location);
-
- $parts = parse_url($location);
- $this->assertArrayHasKey('query', $parts);
-
- // assert fragment is in "application/x-www-form-urlencoded" format
- parse_str($parts['query'], $params);
- $this->assertNotNull($params);
- $this->assertArrayHasKey('id_token', $params);
- $this->assertArrayHasKey('code', $params);
-
- // validate ID Token
- $parts = explode('.', $params['id_token']);
- foreach ($parts as &$part) {
- // Each part is a base64url encoded json string.
- $part = str_replace(array('-', '_'), array('+', '/'), $part);
- $part = base64_decode($part);
- $part = json_decode($part, true);
- }
- list($header, $claims, $signature) = $parts;
-
- $this->assertArrayNotHasKey('email', $claims);
- $this->assertArrayNotHasKey('email_verified', $claims);
- }
-
- private function getTestServer($config = array())
- {
- $config += array(
- 'use_openid_connect' => true,
- 'issuer' => 'test',
- 'id_lifetime' => 3600,
- 'allow_implicit' => true,
- );
-
- $memoryStorage = Bootstrap::getInstance()->getMemoryStorage();
- $memoryStorage->supportedScopes[] = 'email';
- $responseTypes = array(
- 'code' => $code = new AuthorizationCode($memoryStorage),
- 'id_token' => $idToken = new IdToken($memoryStorage, $memoryStorage, $config),
- 'code id_token' => new CodeIdToken($code, $idToken),
- );
-
- $server = new Server($memoryStorage, $config, array(), $responseTypes);
- $server->addGrantType(new ClientCredentials($memoryStorage));
-
- return $server;
- }
-}
diff --git a/library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTest.php b/library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTest.php
deleted file mode 100644
index e772f6be4..000000000
--- a/library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTest.php
+++ /dev/null
@@ -1,184 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\ResponseType;
-
-use OAuth2\Server;
-use OAuth2\Request;
-use OAuth2\Response;
-use OAuth2\Storage\Bootstrap;
-use OAuth2\GrantType\ClientCredentials;
-use OAuth2\Encryption\Jwt;
-
-class IdTokenTest extends \PHPUnit_Framework_TestCase
-{
- public function testValidateAuthorizeRequest()
- {
- $query = array(
- 'response_type' => 'id_token',
- 'redirect_uri' => 'http://adobe.com',
- 'client_id' => 'Test Client ID',
- 'scope' => 'openid',
- 'state' => 'test',
- );
-
- // attempt to do the request without a nonce.
- $server = $this->getTestServer(array('allow_implicit' => true));
- $request = new Request($query);
- $valid = $server->validateAuthorizeRequest($request, $response = new Response());
-
- // Add a nonce and retry.
- $query['nonce'] = 'test';
- $request = new Request($query);
- $valid = $server->validateAuthorizeRequest($request, $response = new Response());
- $this->assertTrue($valid);
- }
-
- public function testHandleAuthorizeRequest()
- {
- // add the test parameters in memory
- $server = $this->getTestServer(array('allow_implicit' => true));
- $request = new Request(array(
- 'response_type' => 'id_token',
- 'redirect_uri' => 'http://adobe.com',
- 'client_id' => 'Test Client ID',
- 'scope' => 'openid email',
- 'state' => 'test',
- 'nonce' => 'test',
- ));
-
- $user_id = 'testuser';
- $server->handleAuthorizeRequest($request, $response = new Response(), true, $user_id);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $location = $response->getHttpHeader('Location');
- $this->assertNotContains('error', $location);
-
- $parts = parse_url($location);
- $this->assertArrayHasKey('fragment', $parts);
- $this->assertFalse(isset($parts['query']));
-
- // assert fragment is in "application/x-www-form-urlencoded" format
- parse_str($parts['fragment'], $params);
- $this->assertNotNull($params);
- $this->assertArrayHasKey('id_token', $params);
- $this->assertArrayNotHasKey('access_token', $params);
- $this->validateIdToken($params['id_token']);
- }
-
- public function testPassInAuthTime()
- {
- $server = $this->getTestServer(array('allow_implicit' => true));
- $request = new Request(array(
- 'response_type' => 'id_token',
- 'redirect_uri' => 'http://adobe.com',
- 'client_id' => 'Test Client ID',
- 'scope' => 'openid email',
- 'state' => 'test',
- 'nonce' => 'test',
- ));
-
- // test with a scalar user id
- $user_id = 'testuser123';
- $server->handleAuthorizeRequest($request, $response = new Response(), true, $user_id);
-
- list($header, $payload, $signature) = $this->extractTokenDataFromResponse($response);
-
- $this->assertTrue(is_array($payload));
- $this->assertArrayHasKey('sub', $payload);
- $this->assertEquals($user_id, $payload['sub']);
- $this->assertArrayHasKey('auth_time', $payload);
-
- // test with an array of user info
- $userInfo = array(
- 'user_id' => 'testuser1234',
- 'auth_time' => date('Y-m-d H:i:s', strtotime('20 minutes ago')
- ));
-
- $server->handleAuthorizeRequest($request, $response = new Response(), true, $userInfo);
-
- list($header, $payload, $signature) = $this->extractTokenDataFromResponse($response);
-
- $this->assertTrue(is_array($payload));
- $this->assertArrayHasKey('sub', $payload);
- $this->assertEquals($userInfo['user_id'], $payload['sub']);
- $this->assertArrayHasKey('auth_time', $payload);
- $this->assertEquals($userInfo['auth_time'], $payload['auth_time']);
- }
-
- private function extractTokenDataFromResponse(Response $response)
- {
- $this->assertEquals($response->getStatusCode(), 302);
- $location = $response->getHttpHeader('Location');
- $this->assertNotContains('error', $location);
-
- $parts = parse_url($location);
- $this->assertArrayHasKey('fragment', $parts);
- $this->assertFalse(isset($parts['query']));
-
- parse_str($parts['fragment'], $params);
- $this->assertNotNull($params);
- $this->assertArrayHasKey('id_token', $params);
- $this->assertArrayNotHasKey('access_token', $params);
-
- list($headb64, $payloadb64, $signature) = explode('.', $params['id_token']);
-
- $jwt = new Jwt();
- $header = json_decode($jwt->urlSafeB64Decode($headb64), true);
- $payload = json_decode($jwt->urlSafeB64Decode($payloadb64), true);
-
- return array($header, $payload, $signature);
- }
-
- private function validateIdToken($id_token)
- {
- $parts = explode('.', $id_token);
- foreach ($parts as &$part) {
- // Each part is a base64url encoded json string.
- $part = str_replace(array('-', '_'), array('+', '/'), $part);
- $part = base64_decode($part);
- $part = json_decode($part, true);
- }
- list($header, $claims, $signature) = $parts;
-
- $this->assertArrayHasKey('iss', $claims);
- $this->assertArrayHasKey('sub', $claims);
- $this->assertArrayHasKey('aud', $claims);
- $this->assertArrayHasKey('iat', $claims);
- $this->assertArrayHasKey('exp', $claims);
- $this->assertArrayHasKey('auth_time', $claims);
- $this->assertArrayHasKey('nonce', $claims);
- $this->assertArrayHasKey('email', $claims);
- $this->assertArrayHasKey('email_verified', $claims);
-
- $this->assertEquals($claims['iss'], 'test');
- $this->assertEquals($claims['aud'], 'Test Client ID');
- $this->assertEquals($claims['nonce'], 'test');
- $this->assertEquals($claims['email'], 'testuser@test.com');
- $duration = $claims['exp'] - $claims['iat'];
- $this->assertEquals($duration, 3600);
- }
-
- private function getTestServer($config = array())
- {
- $config += array(
- 'use_openid_connect' => true,
- 'issuer' => 'test',
- 'id_lifetime' => 3600,
- );
-
- $memoryStorage = Bootstrap::getInstance()->getMemoryStorage();
- $memoryStorage->supportedScopes[] = 'email';
- $storage = array(
- 'client' => $memoryStorage,
- 'scope' => $memoryStorage,
- );
- $responseTypes = array(
- 'id_token' => new IdToken($memoryStorage, $memoryStorage, $config),
- );
-
- $server = new Server($storage, $config, array(), $responseTypes);
- $server->addGrantType(new ClientCredentials($memoryStorage));
-
- return $server;
- }
-}
diff --git a/library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTokenTest.php b/library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTokenTest.php
deleted file mode 100644
index bc564d37b..000000000
--- a/library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTokenTest.php
+++ /dev/null
@@ -1,91 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\ResponseType;
-
-use OAuth2\Server;
-use OAuth2\Request;
-use OAuth2\Response;
-use OAuth2\Storage\Bootstrap;
-use OAuth2\GrantType\ClientCredentials;
-use OAuth2\ResponseType\AccessToken;
-
-class IdTokenTokenTest extends \PHPUnit_Framework_TestCase
-{
-
- public function testHandleAuthorizeRequest()
- {
- // add the test parameters in memory
- $server = $this->getTestServer(array('allow_implicit' => true));
-
- $request = new Request(array(
- 'response_type' => 'id_token token',
- 'redirect_uri' => 'http://adobe.com',
- 'client_id' => 'Test Client ID',
- 'scope' => 'openid',
- 'state' => 'test',
- 'nonce' => 'test',
- ));
-
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- $this->assertEquals($response->getStatusCode(), 302);
- $location = $response->getHttpHeader('Location');
- $this->assertNotContains('error', $location);
-
- $parts = parse_url($location);
- $this->assertArrayHasKey('fragment', $parts);
- $this->assertFalse(isset($parts['query']));
-
- // assert fragment is in "application/x-www-form-urlencoded" format
- parse_str($parts['fragment'], $params);
- $this->assertNotNull($params);
- $this->assertArrayHasKey('id_token', $params);
- $this->assertArrayHasKey('access_token', $params);
-
- // validate ID Token
- $parts = explode('.', $params['id_token']);
- foreach ($parts as &$part) {
- // Each part is a base64url encoded json string.
- $part = str_replace(array('-', '_'), array('+', '/'), $part);
- $part = base64_decode($part);
- $part = json_decode($part, true);
- }
- list($header, $claims, $signature) = $parts;
-
- $this->assertArrayHasKey('iss', $claims);
- $this->assertArrayHasKey('sub', $claims);
- $this->assertArrayHasKey('aud', $claims);
- $this->assertArrayHasKey('iat', $claims);
- $this->assertArrayHasKey('exp', $claims);
- $this->assertArrayHasKey('auth_time', $claims);
- $this->assertArrayHasKey('nonce', $claims);
- $this->assertArrayHasKey('at_hash', $claims);
-
- $this->assertEquals($claims['iss'], 'test');
- $this->assertEquals($claims['aud'], 'Test Client ID');
- $this->assertEquals($claims['nonce'], 'test');
- $duration = $claims['exp'] - $claims['iat'];
- $this->assertEquals($duration, 3600);
- }
-
- private function getTestServer($config = array())
- {
- $config += array(
- 'use_openid_connect' => true,
- 'issuer' => 'test',
- 'id_lifetime' => 3600,
- );
-
- $memoryStorage = Bootstrap::getInstance()->getMemoryStorage();
- $responseTypes = array(
- 'token' => $token = new AccessToken($memoryStorage, $memoryStorage),
- 'id_token' => $idToken = new IdToken($memoryStorage, $memoryStorage, $config),
- 'id_token token' => new IdTokenToken($token, $idToken),
- );
-
- $server = new Server($memoryStorage, $config, array(), $responseTypes);
- $server->addGrantType(new ClientCredentials($memoryStorage));
-
- return $server;
- }
-}
diff --git a/library/oauth2/test/OAuth2/OpenID/Storage/AuthorizationCodeTest.php b/library/oauth2/test/OAuth2/OpenID/Storage/AuthorizationCodeTest.php
deleted file mode 100644
index bdfb085e3..000000000
--- a/library/oauth2/test/OAuth2/OpenID/Storage/AuthorizationCodeTest.php
+++ /dev/null
@@ -1,95 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\Storage;
-
-use OAuth2\Storage\BaseTest;
-use OAuth2\Storage\NullStorage;
-
-class AuthorizationCodeTest extends BaseTest
-{
- /** @dataProvider provideStorage */
- public function testCreateAuthorizationCode($storage)
- {
- if ($storage instanceof NullStorage) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- if (!$storage instanceof AuthorizationCodeInterface) {
- return;
- }
-
- // assert code we are about to add does not exist
- $code = $storage->getAuthorizationCode('new-openid-code');
- $this->assertFalse($code);
-
- // add new code
- $expires = time() + 20;
- $scope = null;
- $id_token = 'fake_id_token';
- $success = $storage->setAuthorizationCode('new-openid-code', 'client ID', 'SOMEUSERID', 'http://example.com', $expires, $scope, $id_token);
- $this->assertTrue($success);
-
- $code = $storage->getAuthorizationCode('new-openid-code');
- $this->assertNotNull($code);
- $this->assertArrayHasKey('authorization_code', $code);
- $this->assertArrayHasKey('client_id', $code);
- $this->assertArrayHasKey('user_id', $code);
- $this->assertArrayHasKey('redirect_uri', $code);
- $this->assertArrayHasKey('expires', $code);
- $this->assertEquals($code['authorization_code'], 'new-openid-code');
- $this->assertEquals($code['client_id'], 'client ID');
- $this->assertEquals($code['user_id'], 'SOMEUSERID');
- $this->assertEquals($code['redirect_uri'], 'http://example.com');
- $this->assertEquals($code['expires'], $expires);
- $this->assertEquals($code['id_token'], $id_token);
-
- // change existing code
- $expires = time() + 42;
- $new_id_token = 'fake_id_token-2';
- $success = $storage->setAuthorizationCode('new-openid-code', 'client ID2', 'SOMEOTHERID', 'http://example.org', $expires, $scope, $new_id_token);
- $this->assertTrue($success);
-
- $code = $storage->getAuthorizationCode('new-openid-code');
- $this->assertNotNull($code);
- $this->assertArrayHasKey('authorization_code', $code);
- $this->assertArrayHasKey('client_id', $code);
- $this->assertArrayHasKey('user_id', $code);
- $this->assertArrayHasKey('redirect_uri', $code);
- $this->assertArrayHasKey('expires', $code);
- $this->assertEquals($code['authorization_code'], 'new-openid-code');
- $this->assertEquals($code['client_id'], 'client ID2');
- $this->assertEquals($code['user_id'], 'SOMEOTHERID');
- $this->assertEquals($code['redirect_uri'], 'http://example.org');
- $this->assertEquals($code['expires'], $expires);
- $this->assertEquals($code['id_token'], $new_id_token);
- }
-
- /** @dataProvider provideStorage */
- public function testRemoveIdTokenFromAuthorizationCode($storage)
- {
- // add new code
- $expires = time() + 20;
- $scope = null;
- $id_token = 'fake_id_token_to_remove';
- $authcode = 'new-openid-code-'.rand();
- $success = $storage->setAuthorizationCode($authcode, 'client ID', 'SOMEUSERID', 'http://example.com', $expires, $scope, $id_token);
- $this->assertTrue($success);
-
- // verify params were set
- $code = $storage->getAuthorizationCode($authcode);
- $this->assertNotNull($code);
- $this->assertArrayHasKey('id_token', $code);
- $this->assertEquals($code['id_token'], $id_token);
-
- // remove the id_token
- $success = $storage->setAuthorizationCode($authcode, 'client ID', 'SOMEUSERID', 'http://example.com', $expires, $scope, null);
-
- // verify the "id_token" is now null
- $code = $storage->getAuthorizationCode($authcode);
- $this->assertNotNull($code);
- $this->assertArrayHasKey('id_token', $code);
- $this->assertEquals($code['id_token'], null);
- }
-}
diff --git a/library/oauth2/test/OAuth2/OpenID/Storage/UserClaimsTest.php b/library/oauth2/test/OAuth2/OpenID/Storage/UserClaimsTest.php
deleted file mode 100644
index 840f6c566..000000000
--- a/library/oauth2/test/OAuth2/OpenID/Storage/UserClaimsTest.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-namespace OAuth2\OpenID\Storage;
-
-use OAuth2\Storage\BaseTest;
-use OAuth2\Storage\NullStorage;
-
-class UserClaimsTest extends BaseTest
-{
- /** @dataProvider provideStorage */
- public function testGetUserClaims($storage)
- {
- if ($storage instanceof NullStorage) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- if (!$storage instanceof UserClaimsInterface) {
- // incompatible storage
- return;
- }
-
- // invalid user
- $claims = $storage->getUserClaims('fake-user', '');
- $this->assertFalse($claims);
-
- // valid user (no scope)
- $claims = $storage->getUserClaims('testuser', '');
-
- /* assert the decoded token is the same */
- $this->assertFalse(isset($claims['email']));
-
- // valid user
- $claims = $storage->getUserClaims('testuser', 'email');
-
- /* assert the decoded token is the same */
- $this->assertEquals($claims['email'], "testuser@test.com");
- $this->assertEquals($claims['email_verified'], true);
- }
-}
diff --git a/library/oauth2/test/OAuth2/RequestTest.php b/library/oauth2/test/OAuth2/RequestTest.php
deleted file mode 100644
index 10db3215c..000000000
--- a/library/oauth2/test/OAuth2/RequestTest.php
+++ /dev/null
@@ -1,98 +0,0 @@
-<?php
-
-namespace OAuth2;
-
-use OAuth2\Request\TestRequest;
-use OAuth2\Storage\Bootstrap;
-use OAuth2\GrantType\AuthorizationCode;
-
-class RequestTest extends \PHPUnit_Framework_TestCase
-{
- public function testRequestOverride()
- {
- $request = new TestRequest();
- $server = $this->getTestServer();
-
- // Smoke test for override request class
- // $server->handleTokenRequest($request, $response = new Response());
- // $this->assertInstanceOf('Response', $response);
- // $server->handleAuthorizeRequest($request, $response = new Response(), true);
- // $this->assertInstanceOf('Response', $response);
- // $response = $server->verifyResourceRequest($request, $response = new Response());
- // $this->assertTrue(is_bool($response));
-
- /*** make some valid requests ***/
-
- // Valid Token Request
- $request->setPost(array(
- 'grant_type' => 'authorization_code',
- 'client_id' => 'Test Client ID',
- 'client_secret' => 'TestSecret',
- 'code' => 'testcode',
- ));
- $server->handleTokenRequest($request, $response = new Response());
- $this->assertEquals($response->getStatusCode(), 200);
- $this->assertNull($response->getParameter('error'));
- $this->assertNotNUll($response->getParameter('access_token'));
- }
-
- public function testHeadersReturnsValueByKey()
- {
- $request = new Request(
- array(),
- array(),
- array(),
- array(),
- array(),
- array(),
- array(),
- array('AUTHORIZATION' => 'Basic secret')
- );
-
- $this->assertEquals('Basic secret', $request->headers('AUTHORIZATION'));
- }
-
- public function testHeadersReturnsDefaultIfHeaderNotPresent()
- {
- $request = new Request();
-
- $this->assertEquals('Bearer', $request->headers('AUTHORIZATION', 'Bearer'));
- }
-
- public function testHeadersIsCaseInsensitive()
- {
- $request = new Request(
- array(),
- array(),
- array(),
- array(),
- array(),
- array(),
- array(),
- array('AUTHORIZATION' => 'Basic secret')
- );
-
- $this->assertEquals('Basic secret', $request->headers('Authorization'));
- }
-
- public function testRequestReturnsPostParamIfNoQueryParamAvailable()
- {
- $request = new Request(
- array(),
- array('client_id' => 'correct')
- );
-
- $this->assertEquals('correct', $request->query('client_id', $request->request('client_id')));
- }
-
- private function getTestServer($config = array())
- {
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $server = new Server($storage, $config);
-
- // Add the two types supported for authorization grant
- $server->addGrantType(new AuthorizationCode($storage));
-
- return $server;
- }
-}
diff --git a/library/oauth2/test/OAuth2/ResponseTest.php b/library/oauth2/test/OAuth2/ResponseTest.php
deleted file mode 100644
index b8149005d..000000000
--- a/library/oauth2/test/OAuth2/ResponseTest.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-
-namespace OAuth2;
-
-class ResponseTest extends \PHPUnit_Framework_TestCase
-{
- public function testRenderAsXml()
- {
- $response = new Response(array(
- 'foo' => 'bar',
- 'halland' => 'oates',
- ));
-
- $string = $response->getResponseBody('xml');
- $this->assertContains('<response><foo>bar</foo><halland>oates</halland></response>', $string);
- }
-}
diff --git a/library/oauth2/test/OAuth2/ResponseType/AccessTokenTest.php b/library/oauth2/test/OAuth2/ResponseType/AccessTokenTest.php
deleted file mode 100644
index 0ed1c82fc..000000000
--- a/library/oauth2/test/OAuth2/ResponseType/AccessTokenTest.php
+++ /dev/null
@@ -1,107 +0,0 @@
-<?php
-
-namespace OAuth2\ResponseType;
-
-use OAuth2\Server;
-use OAuth2\Storage\Memory;
-
-class AccessTokenTest extends \PHPUnit_Framework_TestCase
-{
- public function testRevokeAccessTokenWithTypeHint()
- {
- $tokenStorage = new Memory(array(
- 'access_tokens' => array(
- 'revoke' => array('mytoken'),
- ),
- ));
-
- $this->assertEquals(array('mytoken'), $tokenStorage->getAccessToken('revoke'));
- $accessToken = new AccessToken($tokenStorage);
- $accessToken->revokeToken('revoke', 'access_token');
- $this->assertFalse($tokenStorage->getAccessToken('revoke'));
- }
-
- public function testRevokeAccessTokenWithoutTypeHint()
- {
- $tokenStorage = new Memory(array(
- 'access_tokens' => array(
- 'revoke' => array('mytoken'),
- ),
- ));
-
- $this->assertEquals(array('mytoken'), $tokenStorage->getAccessToken('revoke'));
- $accessToken = new AccessToken($tokenStorage);
- $accessToken->revokeToken('revoke');
- $this->assertFalse($tokenStorage->getAccessToken('revoke'));
- }
-
- public function testRevokeRefreshTokenWithTypeHint()
- {
- $tokenStorage = new Memory(array(
- 'refresh_tokens' => array(
- 'revoke' => array('mytoken'),
- ),
- ));
-
- $this->assertEquals(array('mytoken'), $tokenStorage->getRefreshToken('revoke'));
- $accessToken = new AccessToken(new Memory, $tokenStorage);
- $accessToken->revokeToken('revoke', 'refresh_token');
- $this->assertFalse($tokenStorage->getRefreshToken('revoke'));
- }
-
- public function testRevokeRefreshTokenWithoutTypeHint()
- {
- $tokenStorage = new Memory(array(
- 'refresh_tokens' => array(
- 'revoke' => array('mytoken'),
- ),
- ));
-
- $this->assertEquals(array('mytoken'), $tokenStorage->getRefreshToken('revoke'));
- $accessToken = new AccessToken(new Memory, $tokenStorage);
- $accessToken->revokeToken('revoke');
- $this->assertFalse($tokenStorage->getRefreshToken('revoke'));
- }
-
- public function testRevokeAccessTokenWithRefreshTokenTypeHint()
- {
- $tokenStorage = new Memory(array(
- 'access_tokens' => array(
- 'revoke' => array('mytoken'),
- ),
- ));
-
- $this->assertEquals(array('mytoken'), $tokenStorage->getAccessToken('revoke'));
- $accessToken = new AccessToken($tokenStorage);
- $accessToken->revokeToken('revoke', 'refresh_token');
- $this->assertFalse($tokenStorage->getAccessToken('revoke'));
- }
-
- public function testRevokeAccessTokenWithBogusTypeHint()
- {
- $tokenStorage = new Memory(array(
- 'access_tokens' => array(
- 'revoke' => array('mytoken'),
- ),
- ));
-
- $this->assertEquals(array('mytoken'), $tokenStorage->getAccessToken('revoke'));
- $accessToken = new AccessToken($tokenStorage);
- $accessToken->revokeToken('revoke', 'foo');
- $this->assertFalse($tokenStorage->getAccessToken('revoke'));
- }
-
- public function testRevokeRefreshTokenWithBogusTypeHint()
- {
- $tokenStorage = new Memory(array(
- 'refresh_tokens' => array(
- 'revoke' => array('mytoken'),
- ),
- ));
-
- $this->assertEquals(array('mytoken'), $tokenStorage->getRefreshToken('revoke'));
- $accessToken = new AccessToken(new Memory, $tokenStorage);
- $accessToken->revokeToken('revoke', 'foo');
- $this->assertFalse($tokenStorage->getRefreshToken('revoke'));
- }
-}
diff --git a/library/oauth2/test/OAuth2/ResponseType/JwtAccessTokenTest.php b/library/oauth2/test/OAuth2/ResponseType/JwtAccessTokenTest.php
deleted file mode 100644
index 51b01a927..000000000
--- a/library/oauth2/test/OAuth2/ResponseType/JwtAccessTokenTest.php
+++ /dev/null
@@ -1,160 +0,0 @@
-<?php
-
-namespace OAuth2\ResponseType;
-
-use OAuth2\Server;
-use OAuth2\Response;
-use OAuth2\Request\TestRequest;
-use OAuth2\Storage\Bootstrap;
-use OAuth2\Storage\JwtAccessToken as JwtAccessTokenStorage;
-use OAuth2\GrantType\ClientCredentials;
-use OAuth2\GrantType\UserCredentials;
-use OAuth2\GrantType\RefreshToken;
-use OAuth2\Encryption\Jwt;
-
-class JwtAccessTokenTest extends \PHPUnit_Framework_TestCase
-{
- public function testCreateAccessToken()
- {
- $server = $this->getTestServer();
- $jwtResponseType = $server->getResponseType('token');
-
- $accessToken = $jwtResponseType->createAccessToken('Test Client ID', 123, 'test', false);
- $jwt = new Jwt;
- $decodedAccessToken = $jwt->decode($accessToken['access_token'], null, false);
-
- $this->assertArrayHasKey('id', $decodedAccessToken);
- $this->assertArrayHasKey('jti', $decodedAccessToken);
- $this->assertArrayHasKey('iss', $decodedAccessToken);
- $this->assertArrayHasKey('aud', $decodedAccessToken);
- $this->assertArrayHasKey('exp', $decodedAccessToken);
- $this->assertArrayHasKey('iat', $decodedAccessToken);
- $this->assertArrayHasKey('token_type', $decodedAccessToken);
- $this->assertArrayHasKey('scope', $decodedAccessToken);
-
- $this->assertEquals('https://api.example.com', $decodedAccessToken['iss']);
- $this->assertEquals('Test Client ID', $decodedAccessToken['aud']);
- $this->assertEquals(123, $decodedAccessToken['sub']);
- $delta = $decodedAccessToken['exp'] - $decodedAccessToken['iat'];
- $this->assertEquals(3600, $delta);
- $this->assertEquals($decodedAccessToken['id'], $decodedAccessToken['jti']);
- }
-
- public function testGrantJwtAccessToken()
- {
- // add the test parameters in memory
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'client_credentials', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- ));
- $server->handleTokenRequest($request, $response = new Response());
-
- $this->assertNotNull($response->getParameter('access_token'));
- $this->assertEquals(2, substr_count($response->getParameter('access_token'), '.'));
- }
-
- public function testAccessResourceWithJwtAccessToken()
- {
- // add the test parameters in memory
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'client_credentials', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- ));
- $server->handleTokenRequest($request, $response = new Response());
- $this->assertNotNull($JwtAccessToken = $response->getParameter('access_token'));
-
- // make a call to the resource server using the crypto token
- $request = TestRequest::createPost(array(
- 'access_token' => $JwtAccessToken,
- ));
-
- $this->assertTrue($server->verifyResourceRequest($request));
- }
-
- public function testAccessResourceWithJwtAccessTokenUsingSecondaryStorage()
- {
- // add the test parameters in memory
- $server = $this->getTestServer();
- $request = TestRequest::createPost(array(
- 'grant_type' => 'client_credentials', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- ));
- $server->handleTokenRequest($request, $response = new Response());
- $this->assertNotNull($JwtAccessToken = $response->getParameter('access_token'));
-
- // make a call to the resource server using the crypto token
- $request = TestRequest::createPost(array(
- 'access_token' => $JwtAccessToken,
- ));
-
- // create a resource server with the "memory" storage from the grant server
- $resourceServer = new Server($server->getStorage('client_credentials'));
-
- $this->assertTrue($resourceServer->verifyResourceRequest($request));
- }
-
- public function testJwtAccessTokenWithRefreshToken()
- {
- $server = $this->getTestServer();
-
- // add "UserCredentials" grant type and "JwtAccessToken" response type
- // and ensure "JwtAccessToken" response type has "RefreshToken" storage
- $memoryStorage = Bootstrap::getInstance()->getMemoryStorage();
- $server->addGrantType(new UserCredentials($memoryStorage));
- $server->addGrantType(new RefreshToken($memoryStorage));
- $server->addResponseType(new JwtAccessToken($memoryStorage, $memoryStorage, $memoryStorage), 'token');
-
- $request = TestRequest::createPost(array(
- 'grant_type' => 'password', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'username' => 'test-username', // valid username
- 'password' => 'testpass', // valid password
- ));
-
- // make the call to grant a crypto token
- $server->handleTokenRequest($request, $response = new Response());
- $this->assertNotNull($JwtAccessToken = $response->getParameter('access_token'));
- $this->assertNotNull($refreshToken = $response->getParameter('refresh_token'));
-
- // decode token and make sure refresh_token isn't set
- list($header, $payload, $signature) = explode('.', $JwtAccessToken);
- $decodedToken = json_decode(base64_decode($payload), true);
- $this->assertFalse(array_key_exists('refresh_token', $decodedToken));
-
- // use the refresh token to get another access token
- $request = TestRequest::createPost(array(
- 'grant_type' => 'refresh_token',
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'refresh_token' => $refreshToken,
- ));
-
- $server->handleTokenRequest($request, $response = new Response());
- $this->assertNotNull($response->getParameter('access_token'));
- }
-
- private function getTestServer()
- {
- $memoryStorage = Bootstrap::getInstance()->getMemoryStorage();
-
- $storage = array(
- 'access_token' => new JwtAccessTokenStorage($memoryStorage),
- 'client' => $memoryStorage,
- 'client_credentials' => $memoryStorage,
- );
- $server = new Server($storage);
- $server->addGrantType(new ClientCredentials($memoryStorage));
-
- // make the "token" response type a JwtAccessToken
- $config = array('issuer' => 'https://api.example.com');
- $server->addResponseType(new JwtAccessToken($memoryStorage, $memoryStorage, null, $config));
-
- return $server;
- }
-}
diff --git a/library/oauth2/test/OAuth2/ScopeTest.php b/library/oauth2/test/OAuth2/ScopeTest.php
deleted file mode 100644
index 99f9cf6eb..000000000
--- a/library/oauth2/test/OAuth2/ScopeTest.php
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-
-namespace OAuth2;
-
-use OAuth2\Storage\Memory;
-
-class ScopeTest extends \PHPUnit_Framework_TestCase
-{
- public function testCheckScope()
- {
- $scopeUtil = new Scope();
-
- $this->assertFalse($scopeUtil->checkScope('invalid', 'list of scopes'));
- $this->assertTrue($scopeUtil->checkScope('valid', 'valid and-some other-scopes'));
- $this->assertTrue($scopeUtil->checkScope('valid another-valid', 'valid another-valid and-some other-scopes'));
- // all scopes must match
- $this->assertFalse($scopeUtil->checkScope('valid invalid', 'valid and-some other-scopes'));
- $this->assertFalse($scopeUtil->checkScope('valid valid2 invalid', 'valid valid2 and-some other-scopes'));
- }
-
- public function testScopeStorage()
- {
- $scopeUtil = new Scope();
- $this->assertEquals($scopeUtil->getDefaultScope(), null);
-
- $scopeUtil = new Scope(array(
- 'default_scope' => 'default',
- 'supported_scopes' => array('this', 'that', 'another'),
- ));
- $this->assertEquals($scopeUtil->getDefaultScope(), 'default');
- $this->assertTrue($scopeUtil->scopeExists('this that another', 'client_id'));
-
- $memoryStorage = new Memory(array(
- 'default_scope' => 'base',
- 'supported_scopes' => array('only-this-one'),
- ));
- $scopeUtil = new Scope($memoryStorage);
-
- $this->assertEquals($scopeUtil->getDefaultScope(), 'base');
- $this->assertTrue($scopeUtil->scopeExists('only-this-one', 'client_id'));
- }
-}
diff --git a/library/oauth2/test/OAuth2/ServerTest.php b/library/oauth2/test/OAuth2/ServerTest.php
deleted file mode 100644
index 747e120f5..000000000
--- a/library/oauth2/test/OAuth2/ServerTest.php
+++ /dev/null
@@ -1,684 +0,0 @@
-<?php
-
-namespace OAuth2;
-
-use OAuth2\Request\TestRequest;
-use OAuth2\ResponseType\AuthorizationCode;
-use OAuth2\Storage\Bootstrap;
-
-class ServerTest extends \PHPUnit_Framework_TestCase
-{
- /**
- * @expectedException LogicException OAuth2\Storage\ClientInterface
- **/
- public function testGetAuthorizeControllerWithNoClientStorageThrowsException()
- {
- // must set Client Storage
- $server = new Server();
- $server->getAuthorizeController();
- }
-
- /**
- * @expectedException LogicException OAuth2\Storage\AccessTokenInterface
- **/
- public function testGetAuthorizeControllerWithNoAccessTokenStorageThrowsException()
- {
- // must set AccessToken or AuthorizationCode
- $server = new Server();
- $server->addStorage($this->getMock('OAuth2\Storage\ClientInterface'));
- $server->getAuthorizeController();
- }
-
- public function testGetAuthorizeControllerWithClientStorageAndAccessTokenResponseType()
- {
- // must set AccessToken or AuthorizationCode
- $server = new Server();
- $server->addStorage($this->getMock('OAuth2\Storage\ClientInterface'));
- $server->addResponseType($this->getMock('OAuth2\ResponseType\AccessTokenInterface'));
-
- $this->assertNotNull($server->getAuthorizeController());
- }
-
- public function testGetAuthorizeControllerWithClientStorageAndAuthorizationCodeResponseType()
- {
- // must set AccessToken or AuthorizationCode
- $server = new Server();
- $server->addStorage($this->getMock('OAuth2\Storage\ClientInterface'));
- $server->addResponseType($this->getMock('OAuth2\ResponseType\AuthorizationCodeInterface'));
-
- $this->assertNotNull($server->getAuthorizeController());
- }
-
- /**
- * @expectedException LogicException allow_implicit
- **/
- public function testGetAuthorizeControllerWithClientStorageAndAccessTokenStorageThrowsException()
- {
- // must set AuthorizationCode or AccessToken / implicit
- $server = new Server();
- $server->addStorage($this->getMock('OAuth2\Storage\ClientInterface'));
- $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface'));
-
- $this->assertNotNull($server->getAuthorizeController());
- }
-
- public function testGetAuthorizeControllerWithClientStorageAndAccessTokenStorage()
- {
- // must set AuthorizationCode or AccessToken / implicit
- $server = new Server(array(), array('allow_implicit' => true));
- $server->addStorage($this->getMock('OAuth2\Storage\ClientInterface'));
- $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface'));
-
- $this->assertNotNull($server->getAuthorizeController());
- }
-
- public function testGetAuthorizeControllerWithClientStorageAndAuthorizationCodeStorage()
- {
- // must set AccessToken or AuthorizationCode
- $server = new Server();
- $server->addStorage($this->getMock('OAuth2\Storage\ClientInterface'));
- $server->addStorage($this->getMock('OAuth2\Storage\AuthorizationCodeInterface'));
-
- $this->assertNotNull($server->getAuthorizeController());
- }
-
- /**
- * @expectedException LogicException grant_types
- **/
- public function testGetTokenControllerWithGrantTypeStorageThrowsException()
- {
- $server = new Server();
- $server->getTokenController();
- }
-
- /**
- * @expectedException LogicException OAuth2\Storage\ClientCredentialsInterface
- **/
- public function testGetTokenControllerWithNoClientCredentialsStorageThrowsException()
- {
- $server = new Server();
- $server->addStorage($this->getMock('OAuth2\Storage\UserCredentialsInterface'));
- $server->getTokenController();
- }
-
- /**
- * @expectedException LogicException OAuth2\Storage\AccessTokenInterface
- **/
- public function testGetTokenControllerWithNoAccessTokenStorageThrowsException()
- {
- $server = new Server();
- $server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface'));
- $server->getTokenController();
- }
-
- public function testGetTokenControllerWithAccessTokenAndClientCredentialsStorage()
- {
- $server = new Server();
- $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface'));
- $server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface'));
- $server->getTokenController();
- }
-
- public function testGetTokenControllerAccessTokenStorageAndClientCredentialsStorageAndGrantTypes()
- {
- $server = new Server();
- $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface'));
- $server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface'));
- $server->addGrantType($this->getMockBuilder('OAuth2\GrantType\AuthorizationCode')->disableOriginalConstructor()->getMock());
- $server->getTokenController();
- }
-
- /**
- * @expectedException LogicException OAuth2\Storage\AccessTokenInterface
- **/
- public function testGetResourceControllerWithNoAccessTokenStorageThrowsException()
- {
- $server = new Server();
- $server->getResourceController();
- }
-
- public function testGetResourceControllerWithAccessTokenStorage()
- {
- $server = new Server();
- $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface'));
- $server->getResourceController();
- }
-
- /**
- * @expectedException InvalidArgumentException OAuth2\Storage\AccessTokenInterface
- **/
- public function testAddingStorageWithInvalidClass()
- {
- $server = new Server();
- $server->addStorage(new \StdClass());
- }
-
- /**
- * @expectedException InvalidArgumentException access_token
- **/
- public function testAddingStorageWithInvalidKey()
- {
- $server = new Server();
- $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface'), 'nonexistant_storage');
- }
-
- /**
- * @expectedException InvalidArgumentException OAuth2\Storage\AuthorizationCodeInterface
- **/
- public function testAddingStorageWithInvalidKeyStorageCombination()
- {
- $server = new Server();
- $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface'), 'authorization_code');
- }
-
- public function testAddingStorageWithValidKeyOnlySetsThatKey()
- {
- $server = new Server();
- $server->addStorage($this->getMock('OAuth2\Storage\Memory'), 'access_token');
-
- $reflection = new \ReflectionClass($server);
- $prop = $reflection->getProperty('storages');
- $prop->setAccessible(true);
-
- $storages = $prop->getValue($server); // get the private "storages" property
-
- $this->assertEquals(1, count($storages));
- $this->assertTrue(isset($storages['access_token']));
- $this->assertFalse(isset($storages['authorization_code']));
- }
-
- public function testAddingClientStorageSetsClientCredentialsStorageByDefault()
- {
- $server = new Server();
- $memory = $this->getMock('OAuth2\Storage\Memory');
- $server->addStorage($memory, 'client');
-
- $client_credentials = $server->getStorage('client_credentials');
-
- $this->assertNotNull($client_credentials);
- $this->assertEquals($client_credentials, $memory);
- }
-
- public function testAddStorageWithNullValue()
- {
- $memory = $this->getMock('OAuth2\Storage\Memory');
- $server = new Server($memory);
- $server->addStorage(null, 'refresh_token');
-
- $client_credentials = $server->getStorage('client_credentials');
-
- $this->assertNotNull($client_credentials);
- $this->assertEquals($client_credentials, $memory);
-
- $refresh_token = $server->getStorage('refresh_token');
-
- $this->assertNull($refresh_token);
- }
-
- public function testNewServerWithNullStorageValue()
- {
- $memory = $this->getMock('OAuth2\Storage\Memory');
- $server = new Server(array(
- 'client_credentials' => $memory,
- 'refresh_token' => null,
- ));
-
- $client_credentials = $server->getStorage('client_credentials');
-
- $this->assertNotNull($client_credentials);
- $this->assertEquals($client_credentials, $memory);
-
- $refresh_token = $server->getStorage('refresh_token');
-
- $this->assertNull($refresh_token);
- }
-
- public function testAddingClientCredentialsStorageSetsClientStorageByDefault()
- {
- $server = new Server();
- $memory = $this->getMock('OAuth2\Storage\Memory');
- $server->addStorage($memory, 'client_credentials');
-
- $client = $server->getStorage('client');
-
- $this->assertNotNull($client);
- $this->assertEquals($client, $memory);
- }
-
- public function testSettingClientStorageByDefaultDoesNotOverrideSetStorage()
- {
- $server = new Server();
- $pdo = $this->getMockBuilder('OAuth2\Storage\Pdo')
- ->disableOriginalConstructor()->getMock();
-
- $memory = $this->getMock('OAuth2\Storage\Memory');
-
- $server->addStorage($pdo, 'client');
- $server->addStorage($memory, 'client_credentials');
-
- $client = $server->getStorage('client');
- $client_credentials = $server->getStorage('client_credentials');
-
- $this->assertEquals($client, $pdo);
- $this->assertEquals($client_credentials, $memory);
- }
-
- public function testAddingResponseType()
- {
- $storage = $this->getMock('OAuth2\Storage\Memory');
- $storage
- ->expects($this->any())
- ->method('getClientDetails')
- ->will($this->returnValue(array('client_id' => 'some_client')));
- $storage
- ->expects($this->any())
- ->method('checkRestrictedGrantType')
- ->will($this->returnValue(true));
-
- // add with the "code" key explicitly set
- $codeType = new AuthorizationCode($storage);
- $server = new Server();
- $server->addStorage($storage);
- $server->addResponseType($codeType);
- $request = new Request(array(
- 'response_type' => 'code',
- 'client_id' => 'some_client',
- 'redirect_uri' => 'http://example.com',
- 'state' => 'xyx',
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- // the response is successful
- $this->assertEquals($response->getStatusCode(), 302);
- $parts = parse_url($response->getHttpHeader('Location'));
- parse_str($parts['query'], $query);
- $this->assertTrue(isset($query['code']));
- $this->assertFalse(isset($query['error']));
-
- // add with the "code" key not set
- $codeType = new AuthorizationCode($storage);
- $server = new Server(array($storage), array(), array(), array($codeType));
- $request = new Request(array(
- 'response_type' => 'code',
- 'client_id' => 'some_client',
- 'redirect_uri' => 'http://example.com',
- 'state' => 'xyx',
- ));
- $server->handleAuthorizeRequest($request, $response = new Response(), true);
-
- // the response is successful
- $this->assertEquals($response->getStatusCode(), 302);
- $parts = parse_url($response->getHttpHeader('Location'));
- parse_str($parts['query'], $query);
- $this->assertTrue(isset($query['code']));
- $this->assertFalse(isset($query['error']));
- }
-
- public function testCustomClientAssertionType()
- {
- $request = TestRequest::createPost(array(
- 'grant_type' => 'authorization_code',
- 'client_id' =>'Test Client ID',
- 'code' => 'testcode',
- ));
- // verify the mock clientAssertionType was called as expected
- $clientAssertionType = $this->getMock('OAuth2\ClientAssertionType\ClientAssertionTypeInterface', array('validateRequest', 'getClientId'));
- $clientAssertionType
- ->expects($this->once())
- ->method('validateRequest')
- ->will($this->returnValue(true));
- $clientAssertionType
- ->expects($this->once())
- ->method('getClientId')
- ->will($this->returnValue('Test Client ID'));
-
- // create mock storage
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $server = new Server(array($storage), array(), array(), array(), null, null, $clientAssertionType);
- $server->handleTokenRequest($request, $response = new Response());
- }
-
- public function testHttpBasicConfig()
- {
- // create mock storage
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $server = new Server(array($storage), array(
- 'allow_credentials_in_request_body' => false,
- 'allow_public_clients' => false
- ));
- $server->getTokenController();
- $httpBasic = $server->getClientAssertionType();
-
- $reflection = new \ReflectionClass($httpBasic);
- $prop = $reflection->getProperty('config');
- $prop->setAccessible(true);
-
- $config = $prop->getValue($httpBasic); // get the private "config" property
-
- $this->assertEquals($config['allow_credentials_in_request_body'], false);
- $this->assertEquals($config['allow_public_clients'], false);
- }
-
- public function testRefreshTokenConfig()
- {
- // create mock storage
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $server1 = new Server(array($storage));
- $server2 = new Server(array($storage), array('always_issue_new_refresh_token' => true, 'unset_refresh_token_after_use' => false));
-
- $server1->getTokenController();
- $refreshToken1 = $server1->getGrantType('refresh_token');
-
- $server2->getTokenController();
- $refreshToken2 = $server2->getGrantType('refresh_token');
-
- $reflection1 = new \ReflectionClass($refreshToken1);
- $prop1 = $reflection1->getProperty('config');
- $prop1->setAccessible(true);
-
- $reflection2 = new \ReflectionClass($refreshToken2);
- $prop2 = $reflection2->getProperty('config');
- $prop2->setAccessible(true);
-
- // get the private "config" property
- $config1 = $prop1->getValue($refreshToken1);
- $config2 = $prop2->getValue($refreshToken2);
-
- $this->assertEquals($config1['always_issue_new_refresh_token'], false);
- $this->assertEquals($config2['always_issue_new_refresh_token'], true);
-
- $this->assertEquals($config1['unset_refresh_token_after_use'], true);
- $this->assertEquals($config2['unset_refresh_token_after_use'], false);
- }
-
- /**
- * Test setting "always_issue_new_refresh_token" on a server level
- *
- * @see test/OAuth2/GrantType/RefreshTokenTest::testValidRefreshTokenWithNewRefreshTokenInResponse
- **/
- public function testValidRefreshTokenWithNewRefreshTokenInResponse()
- {
- $storage = Bootstrap::getInstance()->getMemoryStorage();
- $server = new Server($storage, array('always_issue_new_refresh_token' => true));
-
- $request = TestRequest::createPost(array(
- 'grant_type' => 'refresh_token', // valid grant type
- 'client_id' => 'Test Client ID', // valid client id
- 'client_secret' => 'TestSecret', // valid client secret
- 'refresh_token' => 'test-refreshtoken', // valid refresh token
- ));
- $token = $server->grantAccessToken($request, new Response());
- $this->assertTrue(isset($token['refresh_token']), 'refresh token should always refresh');
-
- $refresh_token = $storage->getRefreshToken($token['refresh_token']);
- $this->assertNotNull($refresh_token);
- $this->assertEquals($refresh_token['refresh_token'], $token['refresh_token']);
- $this->assertEquals($refresh_token['client_id'], $request->request('client_id'));
- $this->assertTrue($token['refresh_token'] != 'test-refreshtoken', 'the refresh token returned is not the one used');
- $used_token = $storage->getRefreshToken('test-refreshtoken');
- $this->assertFalse($used_token, 'the refresh token used is no longer valid');
- }
-
- /**
- * @expectedException InvalidArgumentException OAuth2\ResponseType\AuthorizationCodeInterface
- **/
- public function testAddingUnknownResponseTypeThrowsException()
- {
- $server = new Server();
- $server->addResponseType($this->getMock('OAuth2\ResponseType\ResponseTypeInterface'));
- }
-
- /**
- * @expectedException LogicException OAuth2\Storage\PublicKeyInterface
- **/
- public function testUsingJwtAccessTokensWithoutPublicKeyStorageThrowsException()
- {
- $server = new Server(array(), array('use_jwt_access_tokens' => true));
- $server->addGrantType($this->getMock('OAuth2\GrantType\GrantTypeInterface'));
- $server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface'));
- $server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface'));
-
- $server->getTokenController();
- }
-
- public function testUsingJustJwtAccessTokenStorageWithResourceControllerIsOkay()
- {
- $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
- $server = new Server(array($pubkey), array('use_jwt_access_tokens' => true));
-
- $this->assertNotNull($server->getResourceController());
- $this->assertInstanceOf('OAuth2\Storage\PublicKeyInterface', $server->getStorage('public_key'));
- }
-
- /**
- * @expectedException LogicException OAuth2\Storage\ClientInterface
- **/
- public function testUsingJustJwtAccessTokenStorageWithAuthorizeControllerThrowsException()
- {
- $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
- $server = new Server(array($pubkey), array('use_jwt_access_tokens' => true));
- $this->assertNotNull($server->getAuthorizeController());
- }
-
- /**
- * @expectedException LogicException grant_types
- **/
- public function testUsingJustJwtAccessTokenStorageWithTokenControllerThrowsException()
- {
- $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
- $server = new Server(array($pubkey), array('use_jwt_access_tokens' => true));
- $server->getTokenController();
- }
-
- public function testUsingJwtAccessTokenAndClientStorageWithAuthorizeControllerIsOkay()
- {
- $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
- $client = $this->getMock('OAuth2\Storage\ClientInterface');
- $server = new Server(array($pubkey, $client), array('use_jwt_access_tokens' => true, 'allow_implicit' => true));
- $this->assertNotNull($server->getAuthorizeController());
-
- $this->assertInstanceOf('OAuth2\ResponseType\JwtAccessToken', $server->getResponseType('token'));
- }
-
- /**
- * @expectedException LogicException UserClaims
- **/
- public function testUsingOpenIDConnectWithoutUserClaimsThrowsException()
- {
- $client = $this->getMock('OAuth2\Storage\ClientInterface');
- $server = new Server($client, array('use_openid_connect' => true));
-
- $server->getAuthorizeController();
- }
-
- /**
- * @expectedException LogicException PublicKeyInterface
- **/
- public function testUsingOpenIDConnectWithoutPublicKeyThrowsException()
- {
- $client = $this->getMock('OAuth2\Storage\ClientInterface');
- $userclaims = $this->getMock('OAuth2\OPenID\Storage\UserClaimsInterface');
- $server = new Server(array($client, $userclaims), array('use_openid_connect' => true));
-
- $server->getAuthorizeController();
- }
-
- /**
- * @expectedException LogicException issuer
- **/
- public function testUsingOpenIDConnectWithoutIssuerThrowsException()
- {
- $client = $this->getMock('OAuth2\Storage\ClientInterface');
- $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface');
- $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
- $server = new Server(array($client, $userclaims, $pubkey), array('use_openid_connect' => true));
-
- $server->getAuthorizeController();
- }
-
- public function testUsingOpenIDConnectWithIssuerPublicKeyAndUserClaimsIsOkay()
- {
- $client = $this->getMock('OAuth2\Storage\ClientInterface');
- $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface');
- $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
- $server = new Server(array($client, $userclaims, $pubkey), array(
- 'use_openid_connect' => true,
- 'issuer' => 'someguy',
- ));
-
- $server->getAuthorizeController();
-
- $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenInterface', $server->getResponseType('id_token'));
- $this->assertNull($server->getResponseType('id_token token'));
- }
-
- /**
- * @expectedException LogicException OAuth2\ResponseType\AccessTokenInterface
- **/
- public function testUsingOpenIDConnectWithAllowImplicitWithoutTokenStorageThrowsException()
- {
- $client = $this->getMock('OAuth2\Storage\ClientInterface');
- $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface');
- $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
- $server = new Server(array($client, $userclaims, $pubkey), array(
- 'use_openid_connect' => true,
- 'issuer' => 'someguy',
- 'allow_implicit' => true,
- ));
-
- $server->getAuthorizeController();
- }
-
- public function testUsingOpenIDConnectWithAllowImplicitAndUseJwtAccessTokensIsOkay()
- {
- $client = $this->getMock('OAuth2\Storage\ClientInterface');
- $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface');
- $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
- $server = new Server(array($client, $userclaims, $pubkey), array(
- 'use_openid_connect' => true,
- 'issuer' => 'someguy',
- 'allow_implicit' => true,
- 'use_jwt_access_tokens' => true,
- ));
-
- $server->getAuthorizeController();
-
- $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenInterface', $server->getResponseType('id_token'));
- $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenTokenInterface', $server->getResponseType('id_token token'));
- }
-
- public function testUsingOpenIDConnectWithAllowImplicitAndAccessTokenStorageIsOkay()
- {
- $client = $this->getMock('OAuth2\Storage\ClientInterface');
- $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface');
- $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
- $token = $this->getMock('OAuth2\Storage\AccessTokenInterface');
- $server = new Server(array($client, $userclaims, $pubkey, $token), array(
- 'use_openid_connect' => true,
- 'issuer' => 'someguy',
- 'allow_implicit' => true,
- ));
-
- $server->getAuthorizeController();
-
- $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenInterface', $server->getResponseType('id_token'));
- $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenTokenInterface', $server->getResponseType('id_token token'));
- }
-
- public function testUsingOpenIDConnectWithAllowImplicitAndAccessTokenResponseTypeIsOkay()
- {
- $client = $this->getMock('OAuth2\Storage\ClientInterface');
- $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface');
- $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
- // $token = $this->getMock('OAuth2\Storage\AccessTokenInterface');
- $server = new Server(array($client, $userclaims, $pubkey), array(
- 'use_openid_connect' => true,
- 'issuer' => 'someguy',
- 'allow_implicit' => true,
- ));
-
- $token = $this->getMock('OAuth2\ResponseType\AccessTokenInterface');
- $server->addResponseType($token, 'token');
-
- $server->getAuthorizeController();
-
- $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenInterface', $server->getResponseType('id_token'));
- $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenTokenInterface', $server->getResponseType('id_token token'));
- }
-
- /**
- * @expectedException LogicException OAuth2\OpenID\Storage\AuthorizationCodeInterface
- **/
- public function testUsingOpenIDConnectWithAuthorizationCodeStorageThrowsException()
- {
- $client = $this->getMock('OAuth2\Storage\ClientCredentialsInterface');
- $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface');
- $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
- $token = $this->getMock('OAuth2\Storage\AccessTokenInterface');
- $authcode = $this->getMock('OAuth2\Storage\AuthorizationCodeInterface');
-
- $server = new Server(array($client, $userclaims, $pubkey, $token, $authcode), array(
- 'use_openid_connect' => true,
- 'issuer' => 'someguy'
- ));
-
- $server->getTokenController();
-
- $this->assertInstanceOf('OAuth2\OpenID\GrantType\AuthorizationCode', $server->getGrantType('authorization_code'));
- }
-
- public function testUsingOpenIDConnectWithOpenIDAuthorizationCodeStorageCreatesOpenIDAuthorizationCodeGrantType()
- {
- $client = $this->getMock('OAuth2\Storage\ClientCredentialsInterface');
- $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface');
- $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
- $token = $this->getMock('OAuth2\Storage\AccessTokenInterface');
- $authcode = $this->getMock('OAuth2\OpenID\Storage\AuthorizationCodeInterface');
-
- $server = new Server(array($client, $userclaims, $pubkey, $token, $authcode), array(
- 'use_openid_connect' => true,
- 'issuer' => 'someguy'
- ));
-
- $server->getTokenController();
-
- $this->assertInstanceOf('OAuth2\OpenID\GrantType\AuthorizationCode', $server->getGrantType('authorization_code'));
- }
-
- public function testMultipleValuedResponseTypeOrderDoesntMatter()
- {
- $responseType = $this->getMock('OAuth2\OpenID\ResponseType\IdTokenTokenInterface');
- $server = new Server(array(), array(), array(), array(
- 'token id_token' => $responseType,
- ));
-
- $this->assertEquals($responseType, $server->getResponseType('id_token token'));
- }
-
- public function testAddGrantTypeWithoutKey()
- {
- $server = new Server();
- $server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->getMock('OAuth2\Storage\AuthorizationCodeInterface')));
-
- $grantTypes = $server->getGrantTypes();
- $this->assertEquals('authorization_code', key($grantTypes));
- }
-
- public function testAddGrantTypeWithKey()
- {
- $server = new Server();
- $server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->getMock('OAuth2\Storage\AuthorizationCodeInterface')), 'ac');
-
- $grantTypes = $server->getGrantTypes();
- $this->assertEquals('ac', key($grantTypes));
- }
-
- public function testAddGrantTypeWithKeyNotString()
- {
- $server = new Server();
- $server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->getMock('OAuth2\Storage\AuthorizationCodeInterface')), 42);
-
- $grantTypes = $server->getGrantTypes();
- $this->assertEquals('authorization_code', key($grantTypes));
- }
-}
diff --git a/library/oauth2/test/OAuth2/Storage/AccessTokenTest.php b/library/oauth2/test/OAuth2/Storage/AccessTokenTest.php
deleted file mode 100644
index b34e0bfc0..000000000
--- a/library/oauth2/test/OAuth2/Storage/AccessTokenTest.php
+++ /dev/null
@@ -1,102 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-class AccessTokenTest extends BaseTest
-{
- /** @dataProvider provideStorage */
- public function testSetAccessToken(AccessTokenInterface $storage)
- {
- if ($storage instanceof NullStorage) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- // assert token we are about to add does not exist
- $token = $storage->getAccessToken('newtoken');
- $this->assertFalse($token);
-
- // add new token
- $expires = time() + 20;
- $success = $storage->setAccessToken('newtoken', 'client ID', 'SOMEUSERID', $expires);
- $this->assertTrue($success);
-
- $token = $storage->getAccessToken('newtoken');
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- $this->assertArrayHasKey('client_id', $token);
- $this->assertArrayHasKey('user_id', $token);
- $this->assertArrayHasKey('expires', $token);
- $this->assertEquals($token['access_token'], 'newtoken');
- $this->assertEquals($token['client_id'], 'client ID');
- $this->assertEquals($token['user_id'], 'SOMEUSERID');
- $this->assertEquals($token['expires'], $expires);
-
- // change existing token
- $expires = time() + 42;
- $success = $storage->setAccessToken('newtoken', 'client ID2', 'SOMEOTHERID', $expires);
- $this->assertTrue($success);
-
- $token = $storage->getAccessToken('newtoken');
- $this->assertNotNull($token);
- $this->assertArrayHasKey('access_token', $token);
- $this->assertArrayHasKey('client_id', $token);
- $this->assertArrayHasKey('user_id', $token);
- $this->assertArrayHasKey('expires', $token);
- $this->assertEquals($token['access_token'], 'newtoken');
- $this->assertEquals($token['client_id'], 'client ID2');
- $this->assertEquals($token['user_id'], 'SOMEOTHERID');
- $this->assertEquals($token['expires'], $expires);
-
- // add token with scope having an empty string value
- $expires = time() + 42;
- $success = $storage->setAccessToken('newtoken', 'client ID', 'SOMEOTHERID', $expires, '');
- $this->assertTrue($success);
- }
-
- /** @dataProvider provideStorage */
- public function testUnsetAccessToken(AccessTokenInterface $storage)
- {
- if ($storage instanceof NullStorage || !method_exists($storage, 'unsetAccessToken')) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- // assert token we are about to unset does not exist
- $token = $storage->getAccessToken('revokabletoken');
- $this->assertFalse($token);
-
- // add new token
- $expires = time() + 20;
- $success = $storage->setAccessToken('revokabletoken', 'client ID', 'SOMEUSERID', $expires);
- $this->assertTrue($success);
-
- // assert unsetAccessToken returns true
- $result = $storage->unsetAccessToken('revokabletoken');
- $this->assertTrue($result);
-
- // assert token we unset does not exist
- $token = $storage->getAccessToken('revokabletoken');
- $this->assertFalse($token);
- }
-
- /** @dataProvider provideStorage */
- public function testUnsetAccessTokenReturnsFalse(AccessTokenInterface $storage)
- {
- if ($storage instanceof NullStorage || !method_exists($storage, 'unsetAccessToken')) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- // assert token we are about to unset does not exist
- $token = $storage->getAccessToken('nonexistanttoken');
- $this->assertFalse($token);
-
- // assert unsetAccessToken returns false
- $result = $storage->unsetAccessToken('nonexistanttoken');
- $this->assertFalse($result);
- }
-}
diff --git a/library/oauth2/test/OAuth2/Storage/AuthorizationCodeTest.php b/library/oauth2/test/OAuth2/Storage/AuthorizationCodeTest.php
deleted file mode 100644
index 2d901b501..000000000
--- a/library/oauth2/test/OAuth2/Storage/AuthorizationCodeTest.php
+++ /dev/null
@@ -1,106 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-class AuthorizationCodeTest extends BaseTest
-{
- /** @dataProvider provideStorage */
- public function testGetAuthorizationCode(AuthorizationCodeInterface $storage)
- {
- if ($storage instanceof NullStorage) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- // nonexistant client_id
- $details = $storage->getAuthorizationCode('faketoken');
- $this->assertFalse($details);
-
- // valid client_id
- $details = $storage->getAuthorizationCode('testtoken');
- $this->assertNotNull($details);
- }
-
- /** @dataProvider provideStorage */
- public function testSetAuthorizationCode(AuthorizationCodeInterface $storage)
- {
- if ($storage instanceof NullStorage) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- // assert code we are about to add does not exist
- $code = $storage->getAuthorizationCode('newcode');
- $this->assertFalse($code);
-
- // add new code
- $expires = time() + 20;
- $success = $storage->setAuthorizationCode('newcode', 'client ID', 'SOMEUSERID', 'http://example.com', $expires);
- $this->assertTrue($success);
-
- $code = $storage->getAuthorizationCode('newcode');
- $this->assertNotNull($code);
- $this->assertArrayHasKey('authorization_code', $code);
- $this->assertArrayHasKey('client_id', $code);
- $this->assertArrayHasKey('user_id', $code);
- $this->assertArrayHasKey('redirect_uri', $code);
- $this->assertArrayHasKey('expires', $code);
- $this->assertEquals($code['authorization_code'], 'newcode');
- $this->assertEquals($code['client_id'], 'client ID');
- $this->assertEquals($code['user_id'], 'SOMEUSERID');
- $this->assertEquals($code['redirect_uri'], 'http://example.com');
- $this->assertEquals($code['expires'], $expires);
-
- // change existing code
- $expires = time() + 42;
- $success = $storage->setAuthorizationCode('newcode', 'client ID2', 'SOMEOTHERID', 'http://example.org', $expires);
- $this->assertTrue($success);
-
- $code = $storage->getAuthorizationCode('newcode');
- $this->assertNotNull($code);
- $this->assertArrayHasKey('authorization_code', $code);
- $this->assertArrayHasKey('client_id', $code);
- $this->assertArrayHasKey('user_id', $code);
- $this->assertArrayHasKey('redirect_uri', $code);
- $this->assertArrayHasKey('expires', $code);
- $this->assertEquals($code['authorization_code'], 'newcode');
- $this->assertEquals($code['client_id'], 'client ID2');
- $this->assertEquals($code['user_id'], 'SOMEOTHERID');
- $this->assertEquals($code['redirect_uri'], 'http://example.org');
- $this->assertEquals($code['expires'], $expires);
-
- // add new code with scope having an empty string value
- $expires = time() + 20;
- $success = $storage->setAuthorizationCode('newcode', 'client ID', 'SOMEUSERID', 'http://example.com', $expires, '');
- $this->assertTrue($success);
- }
-
- /** @dataProvider provideStorage */
- public function testExpireAccessToken(AccessTokenInterface $storage)
- {
- if ($storage instanceof NullStorage) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- // create a valid code
- $expires = time() + 20;
- $success = $storage->setAuthorizationCode('code-to-expire', 'client ID', 'SOMEUSERID', 'http://example.com', time() + 20);
- $this->assertTrue($success);
-
- // verify the new code exists
- $code = $storage->getAuthorizationCode('code-to-expire');
- $this->assertNotNull($code);
-
- $this->assertArrayHasKey('authorization_code', $code);
- $this->assertEquals($code['authorization_code'], 'code-to-expire');
-
- // now expire the code and ensure it's no longer available
- $storage->expireAuthorizationCode('code-to-expire');
- $code = $storage->getAuthorizationCode('code-to-expire');
- $this->assertFalse($code);
- }
-}
diff --git a/library/oauth2/test/OAuth2/Storage/ClientCredentialsTest.php b/library/oauth2/test/OAuth2/Storage/ClientCredentialsTest.php
deleted file mode 100644
index 15289af30..000000000
--- a/library/oauth2/test/OAuth2/Storage/ClientCredentialsTest.php
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-class ClientCredentialsTest extends BaseTest
-{
- /** @dataProvider provideStorage */
- public function testCheckClientCredentials(ClientCredentialsInterface $storage)
- {
- if ($storage instanceof NullStorage) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- // nonexistant client_id
- $pass = $storage->checkClientCredentials('fakeclient', 'testpass');
- $this->assertFalse($pass);
-
- // invalid password
- $pass = $storage->checkClientCredentials('oauth_test_client', 'invalidcredentials');
- $this->assertFalse($pass);
-
- // valid credentials
- $pass = $storage->checkClientCredentials('oauth_test_client', 'testpass');
- $this->assertTrue($pass);
- }
-}
diff --git a/library/oauth2/test/OAuth2/Storage/ClientTest.php b/library/oauth2/test/OAuth2/Storage/ClientTest.php
deleted file mode 100644
index 6a5cc0b49..000000000
--- a/library/oauth2/test/OAuth2/Storage/ClientTest.php
+++ /dev/null
@@ -1,110 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-class ClientTest extends BaseTest
-{
- /** @dataProvider provideStorage */
- public function testGetClientDetails(ClientInterface $storage)
- {
- if ($storage instanceof NullStorage) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- // nonexistant client_id
- $details = $storage->getClientDetails('fakeclient');
- $this->assertFalse($details);
-
- // valid client_id
- $details = $storage->getClientDetails('oauth_test_client');
- $this->assertNotNull($details);
- $this->assertArrayHasKey('client_id', $details);
- $this->assertArrayHasKey('client_secret', $details);
- $this->assertArrayHasKey('redirect_uri', $details);
- }
-
- /** @dataProvider provideStorage */
- public function testCheckRestrictedGrantType(ClientInterface $storage)
- {
- if ($storage instanceof NullStorage) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- // Check invalid
- $pass = $storage->checkRestrictedGrantType('oauth_test_client', 'authorization_code');
- $this->assertFalse($pass);
-
- // Check valid
- $pass = $storage->checkRestrictedGrantType('oauth_test_client', 'implicit');
- $this->assertTrue($pass);
- }
-
- /** @dataProvider provideStorage */
- public function testGetAccessToken(ClientInterface $storage)
- {
- if ($storage instanceof NullStorage) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- // nonexistant client_id
- $details = $storage->getAccessToken('faketoken');
- $this->assertFalse($details);
-
- // valid client_id
- $details = $storage->getAccessToken('testtoken');
- $this->assertNotNull($details);
- }
-
- /** @dataProvider provideStorage */
- public function testIsPublicClient(ClientInterface $storage)
- {
- if ($storage instanceof NullStorage) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- $publicClientId = 'public-client-'.rand();
- $confidentialClientId = 'confidential-client-'.rand();
-
- // create a new client
- $success1 = $storage->setClientDetails($publicClientId, '');
- $success2 = $storage->setClientDetails($confidentialClientId, 'some-secret');
- $this->assertTrue($success1);
- $this->assertTrue($success2);
-
- // assert isPublicClient for both
- $this->assertTrue($storage->isPublicClient($publicClientId));
- $this->assertFalse($storage->isPublicClient($confidentialClientId));
- }
-
- /** @dataProvider provideStorage */
- public function testSaveClient(ClientInterface $storage)
- {
- if ($storage instanceof NullStorage) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- $clientId = 'some-client-'.rand();
-
- // create a new client
- $success = $storage->setClientDetails($clientId, 'somesecret', 'http://test.com', 'client_credentials', 'clientscope1', 'brent@brentertainment.com');
- $this->assertTrue($success);
-
- // valid client_id
- $details = $storage->getClientDetails($clientId);
- $this->assertEquals($details['client_secret'], 'somesecret');
- $this->assertEquals($details['redirect_uri'], 'http://test.com');
- $this->assertEquals($details['grant_types'], 'client_credentials');
- $this->assertEquals($details['scope'], 'clientscope1');
- $this->assertEquals($details['user_id'], 'brent@brentertainment.com');
- }
-}
diff --git a/library/oauth2/test/OAuth2/Storage/DynamoDBTest.php b/library/oauth2/test/OAuth2/Storage/DynamoDBTest.php
deleted file mode 100644
index 2147f0914..000000000
--- a/library/oauth2/test/OAuth2/Storage/DynamoDBTest.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-class DynamoDBTest extends BaseTest
-{
- public function testGetDefaultScope()
- {
- $client = $this->getMockBuilder('\Aws\DynamoDb\DynamoDbClient')
- ->disableOriginalConstructor()
- ->setMethods(array('query'))
- ->getMock();
-
- $return = $this->getMockBuilder('\Guzzle\Service\Resource\Model')
- ->setMethods(array('count', 'toArray'))
- ->getMock();
-
- $data = array(
- 'Items' => array(),
- 'Count' => 0,
- 'ScannedCount'=> 0
- );
-
- $return->expects($this->once())
- ->method('count')
- ->will($this->returnValue(count($data)));
-
- $return->expects($this->once())
- ->method('toArray')
- ->will($this->returnValue($data));
-
- // should return null default scope if none is set in database
- $client->expects($this->once())
- ->method('query')
- ->will($this->returnValue($return));
-
- $storage = new DynamoDB($client);
- $this->assertNull($storage->getDefaultScope());
- }
-}
diff --git a/library/oauth2/test/OAuth2/Storage/JwtAccessTokenTest.php b/library/oauth2/test/OAuth2/Storage/JwtAccessTokenTest.php
deleted file mode 100644
index a6acbea1f..000000000
--- a/library/oauth2/test/OAuth2/Storage/JwtAccessTokenTest.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-use OAuth2\Encryption\Jwt;
-
-class JwtAccessTokenTest extends BaseTest
-{
- /** @dataProvider provideStorage */
- public function testSetAccessToken($storage)
- {
- if (!$storage instanceof PublicKey) {
- // incompatible storage
- return;
- }
-
- $crypto = new jwtAccessToken($storage);
-
- $publicKeyStorage = Bootstrap::getInstance()->getMemoryStorage();
- $encryptionUtil = new Jwt();
-
- $jwtAccessToken = array(
- 'access_token' => rand(),
- 'expires' => time() + 100,
- 'scope' => 'foo',
- );
-
- $token = $encryptionUtil->encode($jwtAccessToken, $storage->getPrivateKey(), $storage->getEncryptionAlgorithm());
-
- $this->assertNotNull($token);
-
- $tokenData = $crypto->getAccessToken($token);
-
- $this->assertTrue(is_array($tokenData));
-
- /* assert the decoded token is the same */
- $this->assertEquals($tokenData['access_token'], $jwtAccessToken['access_token']);
- $this->assertEquals($tokenData['expires'], $jwtAccessToken['expires']);
- $this->assertEquals($tokenData['scope'], $jwtAccessToken['scope']);
- }
-}
diff --git a/library/oauth2/test/OAuth2/Storage/JwtBearerTest.php b/library/oauth2/test/OAuth2/Storage/JwtBearerTest.php
deleted file mode 100644
index d0ab9b899..000000000
--- a/library/oauth2/test/OAuth2/Storage/JwtBearerTest.php
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-class JwtBearerTest extends BaseTest
-{
- /** @dataProvider provideStorage */
- public function testGetClientKey(JwtBearerInterface $storage)
- {
- if ($storage instanceof NullStorage) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- // nonexistant client_id
- $key = $storage->getClientKey('this-is-not-real', 'nor-is-this');
- $this->assertFalse($key);
-
- // valid client_id and subject
- $key = $storage->getClientKey('oauth_test_client', 'test_subject');
- $this->assertNotNull($key);
- $this->assertEquals($key, Bootstrap::getInstance()->getTestPublicKey());
- }
-}
diff --git a/library/oauth2/test/OAuth2/Storage/PdoTest.php b/library/oauth2/test/OAuth2/Storage/PdoTest.php
deleted file mode 100644
index 57eb39072..000000000
--- a/library/oauth2/test/OAuth2/Storage/PdoTest.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-class PdoTest extends BaseTest
-{
- public function testCreatePdoStorageUsingPdoClass()
- {
- $pdo = new \PDO(sprintf('sqlite://%s', Bootstrap::getInstance()->getSqliteDir()));
- $storage = new Pdo($pdo);
-
- $this->assertNotNull($storage->getClientDetails('oauth_test_client'));
- }
-
- public function testCreatePdoStorageUsingDSN()
- {
- $dsn = sprintf('sqlite://%s', Bootstrap::getInstance()->getSqliteDir());
- $storage = new Pdo($dsn);
-
- $this->assertNotNull($storage->getClientDetails('oauth_test_client'));
- }
-
- public function testCreatePdoStorageUsingConfig()
- {
- $config = array('dsn' => sprintf('sqlite://%s', Bootstrap::getInstance()->getSqliteDir()));
- $storage = new Pdo($config);
-
- $this->assertNotNull($storage->getClientDetails('oauth_test_client'));
- }
-
- /**
- * @expectedException InvalidArgumentException dsn
- */
- public function testCreatePdoStorageWithoutDSNThrowsException()
- {
- $config = array('username' => 'brent', 'password' => 'brentisaballer');
- $storage = new Pdo($config);
- }
-}
diff --git a/library/oauth2/test/OAuth2/Storage/PublicKeyTest.php b/library/oauth2/test/OAuth2/Storage/PublicKeyTest.php
deleted file mode 100644
index f85195870..000000000
--- a/library/oauth2/test/OAuth2/Storage/PublicKeyTest.php
+++ /dev/null
@@ -1,29 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-class PublicKeyTest extends BaseTest
-{
- /** @dataProvider provideStorage */
- public function testSetAccessToken($storage)
- {
- if ($storage instanceof NullStorage) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- if (!$storage instanceof PublicKeyInterface) {
- // incompatible storage
- return;
- }
-
- $configDir = Bootstrap::getInstance()->getConfigDir();
- $globalPublicKey = file_get_contents($configDir.'/keys/id_rsa.pub');
- $globalPrivateKey = file_get_contents($configDir.'/keys/id_rsa');
-
- /* assert values from storage */
- $this->assertEquals($storage->getPublicKey(), $globalPublicKey);
- $this->assertEquals($storage->getPrivateKey(), $globalPrivateKey);
- }
-}
diff --git a/library/oauth2/test/OAuth2/Storage/RefreshTokenTest.php b/library/oauth2/test/OAuth2/Storage/RefreshTokenTest.php
deleted file mode 100644
index 314c93195..000000000
--- a/library/oauth2/test/OAuth2/Storage/RefreshTokenTest.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-class RefreshTokenTest extends BaseTest
-{
- /** @dataProvider provideStorage */
- public function testSetRefreshToken(RefreshTokenInterface $storage)
- {
- if ($storage instanceof NullStorage) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- // assert token we are about to add does not exist
- $token = $storage->getRefreshToken('refreshtoken');
- $this->assertFalse($token);
-
- // add new token
- $expires = time() + 20;
- $success = $storage->setRefreshToken('refreshtoken', 'client ID', 'SOMEUSERID', $expires);
- $this->assertTrue($success);
-
- $token = $storage->getRefreshToken('refreshtoken');
- $this->assertNotNull($token);
- $this->assertArrayHasKey('refresh_token', $token);
- $this->assertArrayHasKey('client_id', $token);
- $this->assertArrayHasKey('user_id', $token);
- $this->assertArrayHasKey('expires', $token);
- $this->assertEquals($token['refresh_token'], 'refreshtoken');
- $this->assertEquals($token['client_id'], 'client ID');
- $this->assertEquals($token['user_id'], 'SOMEUSERID');
- $this->assertEquals($token['expires'], $expires);
-
- // add token with scope having an empty string value
- $expires = time() + 20;
- $success = $storage->setRefreshToken('refreshtoken2', 'client ID', 'SOMEUSERID', $expires, '');
- $this->assertTrue($success);
- }
-}
diff --git a/library/oauth2/test/OAuth2/Storage/ScopeTest.php b/library/oauth2/test/OAuth2/Storage/ScopeTest.php
deleted file mode 100644
index fd1edeb93..000000000
--- a/library/oauth2/test/OAuth2/Storage/ScopeTest.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-use OAuth2\Scope;
-
-class ScopeTest extends BaseTest
-{
- /** @dataProvider provideStorage */
- public function testScopeExists($storage)
- {
- if ($storage instanceof NullStorage) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- if (!$storage instanceof ScopeInterface) {
- // incompatible storage
- return;
- }
-
- //Test getting scopes
- $scopeUtil = new Scope($storage);
- $this->assertTrue($scopeUtil->scopeExists('supportedscope1'));
- $this->assertTrue($scopeUtil->scopeExists('supportedscope1 supportedscope2 supportedscope3'));
- $this->assertFalse($scopeUtil->scopeExists('fakescope'));
- $this->assertFalse($scopeUtil->scopeExists('supportedscope1 supportedscope2 supportedscope3 fakescope'));
- }
-
- /** @dataProvider provideStorage */
- public function testGetDefaultScope($storage)
- {
- if ($storage instanceof NullStorage) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- if (!$storage instanceof ScopeInterface) {
- // incompatible storage
- return;
- }
-
- // test getting default scope
- $scopeUtil = new Scope($storage);
- $expected = explode(' ', $scopeUtil->getDefaultScope());
- $actual = explode(' ', 'defaultscope1 defaultscope2');
- sort($expected);
- sort($actual);
- $this->assertEquals($expected, $actual);
- }
-}
diff --git a/library/oauth2/test/OAuth2/Storage/UserCredentialsTest.php b/library/oauth2/test/OAuth2/Storage/UserCredentialsTest.php
deleted file mode 100644
index 65655a6b2..000000000
--- a/library/oauth2/test/OAuth2/Storage/UserCredentialsTest.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-class UserCredentialsTest extends BaseTest
-{
- /** @dataProvider provideStorage */
- public function testCheckUserCredentials(UserCredentialsInterface $storage)
- {
- if ($storage instanceof NullStorage) {
- $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage());
-
- return;
- }
-
- // create a new user for testing
- $success = $storage->setUser('testusername', 'testpass', 'Test', 'User');
- $this->assertTrue($success);
-
- // correct credentials
- $this->assertTrue($storage->checkUserCredentials('testusername', 'testpass'));
- // invalid password
- $this->assertFalse($storage->checkUserCredentials('testusername', 'fakepass'));
- // invalid username
- $this->assertFalse($storage->checkUserCredentials('fakeusername', 'testpass'));
-
- // invalid username
- $this->assertFalse($storage->getUserDetails('fakeusername'));
-
- // ensure all properties are set
- $user = $storage->getUserDetails('testusername');
- $this->assertTrue($user !== false);
- $this->assertArrayHasKey('user_id', $user);
- $this->assertArrayHasKey('first_name', $user);
- $this->assertArrayHasKey('last_name', $user);
- $this->assertEquals($user['user_id'], 'testusername');
- $this->assertEquals($user['first_name'], 'Test');
- $this->assertEquals($user['last_name'], 'User');
- }
-}
diff --git a/library/oauth2/test/OAuth2/TokenType/BearerTest.php b/library/oauth2/test/OAuth2/TokenType/BearerTest.php
deleted file mode 100644
index a2e000e22..000000000
--- a/library/oauth2/test/OAuth2/TokenType/BearerTest.php
+++ /dev/null
@@ -1,58 +0,0 @@
-<?php
-
-namespace OAuth2\TokenType;
-
-use OAuth2\Request\TestRequest;
-use OAuth2\Response;
-
-class BearerTest extends \PHPUnit_Framework_TestCase
-{
- public function testValidContentTypeWithCharset()
- {
- $bearer = new Bearer();
- $request = TestRequest::createPost(array(
- 'access_token' => 'ThisIsMyAccessToken'
- ));
- $request->server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=UTF-8';
-
- $param = $bearer->getAccessTokenParameter($request, $response = new Response());
- $this->assertEquals($param, 'ThisIsMyAccessToken');
- }
-
- public function testInvalidContentType()
- {
- $bearer = new Bearer();
- $request = TestRequest::createPost(array(
- 'access_token' => 'ThisIsMyAccessToken'
- ));
- $request->server['CONTENT_TYPE'] = 'application/json; charset=UTF-8';
-
- $param = $bearer->getAccessTokenParameter($request, $response = new Response());
- $this->assertNull($param);
- $this->assertEquals($response->getStatusCode(), 400);
- $this->assertEquals($response->getParameter('error'), 'invalid_request');
- $this->assertEquals($response->getParameter('error_description'), 'The content type for POST requests must be "application/x-www-form-urlencoded"');
- }
-
- public function testValidRequestUsingAuthorizationHeader()
- {
- $bearer = new Bearer();
- $request = new TestRequest();
- $request->headers['AUTHORIZATION'] = 'Bearer MyToken';
- $request->server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=UTF-8';
-
- $param = $bearer->getAccessTokenParameter($request, $response = new Response());
- $this->assertEquals('MyToken', $param);
- }
-
- public function testValidRequestUsingAuthorizationHeaderCaseInsensitive()
- {
- $bearer = new Bearer();
- $request = new TestRequest();
- $request->server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=UTF-8';
- $request->headers['Authorization'] = 'Bearer MyToken';
-
- $param = $bearer->getAccessTokenParameter($request, $response = new Response());
- $this->assertEquals('MyToken', $param);
- }
-}
diff --git a/library/oauth2/test/bootstrap.php b/library/oauth2/test/bootstrap.php
deleted file mode 100644
index 0a4af0716..000000000
--- a/library/oauth2/test/bootstrap.php
+++ /dev/null
@@ -1,12 +0,0 @@
-<?php
-
-require_once(dirname(__FILE__).'/../src/OAuth2/Autoloader.php');
-OAuth2\Autoloader::register();
-
-// register test classes
-OAuth2\Autoloader::register(dirname(__FILE__).'/lib');
-
-// register vendors if possible
-if (file_exists(__DIR__.'/../vendor/autoload.php')) {
- require_once(__DIR__.'/../vendor/autoload.php');
-}
diff --git a/library/oauth2/test/cleanup.php b/library/oauth2/test/cleanup.php
deleted file mode 100644
index 8663a901b..000000000
--- a/library/oauth2/test/cleanup.php
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-
-require_once(dirname(__FILE__).'/../src/OAuth2/Autoloader.php');
-OAuth2\Autoloader::register();
-
-// register test classes
-OAuth2\Autoloader::register(dirname(__FILE__).'/lib');
-
-// register vendors if possible
-if (file_exists(__DIR__.'/../vendor/autoload.php')) {
- require_once(__DIR__.'/../vendor/autoload.php');
-}
-
-// remove the dynamoDB database that was created for this build
-OAuth2\Storage\Bootstrap::getInstance()->cleanupTravisDynamoDb();
diff --git a/library/oauth2/test/config/keys/id_rsa b/library/oauth2/test/config/keys/id_rsa
deleted file mode 100644
index e8b9eff2d..000000000
--- a/library/oauth2/test/config/keys/id_rsa
+++ /dev/null
@@ -1,15 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIICXQIBAAKBgQC8fpi06NfVYHAOAnxNMVnTXr/ptsLsNjP+uAt2eO0cc5J9H5XV
-8lFVujOrRu/JWi1TDmAvOaf/6A3BphIA1Pwp0AAqlZdwizIum8j0KzpsGYH5qReN
-QDwF3oUSKMsQCCGCDHrDYifG/pRi9bN1ZVjEXPr35HJuBe+FQpZTs8DewwIDAQAB
-AoGARfNxNknmtx/n1bskZ/01iZRzAge6BLEE0LV6Q4gS7mkRZu/Oyiv39Sl5vUlA
-+WdGxLjkBwKNjxGN8Vxw9/ASd8rSsqeAUYIwAeifXrHhj5DBPQT/pDPkeFnp9B1w
-C6jo+3AbBQ4/b0ONSIEnCL2xGGglSIAxO17T1ViXp7lzXPECQQDe63nkRdWM0OCb
-oaHQPT3E26224maIstrGFUdt9yw3yJf4bOF7TtiPLlLuHsTTge3z+fG6ntC0xG56
-1cl37C3ZAkEA2HdVcRGugNp/qmVz4LJTpD+WZKi73PLAO47wDOrYh9Pn2I6fcEH0
-CPnggt1ko4ujvGzFTvRH64HXa6aPCv1j+wJBAMQMah3VQPNf/DlDVFEUmw9XeBZg
-VHaifX851aEjgXLp6qVj9IYCmLiLsAmVa9rr6P7p8asD418nZlaHUHE0eDkCQQCr
-uxis6GMx1Ka971jcJX2X696LoxXPd0KsvXySMupv79yagKPa8mgBiwPjrnK+EPVo
-cj6iochA/bSCshP/mwFrAkBHEKPi6V6gb94JinCT7x3weahbdp6bJ6/nzBH/p9VA
-HoT1JtwNFhGv9BCjmDydshQHfSWpY9NxlccBKL7ITm8R
------END RSA PRIVATE KEY----- \ No newline at end of file
diff --git a/library/oauth2/test/config/keys/id_rsa.pub b/library/oauth2/test/config/keys/id_rsa.pub
deleted file mode 100644
index 1ac15f5eb..000000000
--- a/library/oauth2/test/config/keys/id_rsa.pub
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICiDCCAfGgAwIBAgIBADANBgkqhkiG9w0BAQQFADA9MQswCQYDVQQGEwJVUzEL
-MAkGA1UECBMCVVQxITAfBgNVBAoTGFZpZ25ldHRlIENvcnBvcmF0aW9uIFNCWDAe
-Fw0xMTEwMTUwMzE4MjdaFw0zMTEwMTAwMzE4MjdaMD0xCzAJBgNVBAYTAlVTMQsw
-CQYDVQQIEwJVVDEhMB8GA1UEChMYVmlnbmV0dGUgQ29ycG9yYXRpb24gU0JYMIGf
-MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8fpi06NfVYHAOAnxNMVnTXr/ptsLs
-NjP+uAt2eO0cc5J9H5XV8lFVujOrRu/JWi1TDmAvOaf/6A3BphIA1Pwp0AAqlZdw
-izIum8j0KzpsGYH5qReNQDwF3oUSKMsQCCGCDHrDYifG/pRi9bN1ZVjEXPr35HJu
-Be+FQpZTs8DewwIDAQABo4GXMIGUMB0GA1UdDgQWBBRe8hrEXm+Yim4YlD5Nx+1K
-vCYs9DBlBgNVHSMEXjBcgBRe8hrEXm+Yim4YlD5Nx+1KvCYs9KFBpD8wPTELMAkG
-A1UEBhMCVVMxCzAJBgNVBAgTAlVUMSEwHwYDVQQKExhWaWduZXR0ZSBDb3Jwb3Jh
-dGlvbiBTQliCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBjhyRD
-lM7vnLn6drgQVftW5V9nDFAyPAuiGvMIKFSbiAf1PxXCRn5sfJquwWKsJUi4ZGNl
-aViXdFmN6/F13PSM+yg63tpKy0fYqMbTM+Oe5WuSHkSW1VuYNHV+24adgNk/FRDL
-FRrlM1f6s9VTLWvwGItjfrof0Ba8Uq7ZDSb9Xg==
------END CERTIFICATE----- \ No newline at end of file
diff --git a/library/oauth2/test/config/storage.json b/library/oauth2/test/config/storage.json
deleted file mode 100644
index a31d3bca2..000000000
--- a/library/oauth2/test/config/storage.json
+++ /dev/null
@@ -1,181 +0,0 @@
-{
- "authorization_codes": {
- "testcode": {
- "client_id": "Test Client ID",
- "user_id": "",
- "redirect_uri": "",
- "expires": "9999999999",
- "id_token": "IDTOKEN"
- },
- "testcode-with-scope": {
- "client_id": "Test Client ID",
- "user_id": "",
- "redirect_uri": "",
- "expires": "9999999999",
- "scope": "scope1 scope2"
- },
- "testcode-expired": {
- "client_id": "Test Client ID",
- "user_id": "",
- "redirect_uri": "",
- "expires": "1356998400"
- },
- "testcode-empty-secret": {
- "client_id": "Test Client ID Empty Secret",
- "user_id": "",
- "redirect_uri": "",
- "expires": "9999999999"
- },
- "testcode-openid": {
- "client_id": "Test Client ID",
- "user_id": "",
- "redirect_uri": "",
- "expires": "9999999999",
- "id_token": "test_id_token"
- }
- },
- "client_credentials" : {
- "Test Client ID": {
- "client_secret": "TestSecret"
- },
- "Test Client ID with Redirect Uri": {
- "client_secret": "TestSecret2",
- "redirect_uri": "http://brentertainment.com"
- },
- "Test Client ID with Buggy Redirect Uri": {
- "client_secret": "TestSecret2",
- "redirect_uri": " http://brentertainment.com"
- },
- "Test Client ID with Multiple Redirect Uris": {
- "client_secret": "TestSecret3",
- "redirect_uri": "http://brentertainment.com http://morehazards.com"
- },
- "Test Client ID with Redirect Uri Parts": {
- "client_secret": "TestSecret4",
- "redirect_uri": "http://user:pass@brentertainment.com:2222/authorize/cb?auth_type=oauth&test=true"
- },
- "Test Some Other Client": {
- "client_secret": "TestSecret3"
- },
- "Test Client ID Empty Secret": {
- "client_secret": ""
- },
- "Test Client ID For Password Grant": {
- "grant_types": "password",
- "client_secret": ""
- },
- "Client ID With User ID": {
- "client_secret": "TestSecret",
- "user_id": "brent@brentertainment.com"
- },
- "oauth_test_client": {
- "client_secret": "testpass",
- "grant_types": "implicit password"
- }
- },
- "user_credentials" : {
- "test-username": {
- "password": "testpass"
- },
- "testusername": {
- "password": "testpass"
- },
- "testuser": {
- "password": "password",
- "email": "testuser@test.com",
- "email_verified": true
- },
- "johndoe": {
- "password": "password"
- }
- },
- "refresh_tokens" : {
- "test-refreshtoken": {
- "refresh_token": "test-refreshtoken",
- "client_id": "Test Client ID",
- "user_id": "test-username",
- "expires": 0,
- "scope": null
- },
- "test-refreshtoken-with-scope": {
- "refresh_token": "test-refreshtoken",
- "client_id": "Test Client ID",
- "user_id": "test-username",
- "expires": 0,
- "scope": "scope1 scope2"
- }
- },
- "access_tokens" : {
- "accesstoken-expired": {
- "access_token": "accesstoken-expired",
- "client_id": "Test Client ID",
- "expires": 1234567,
- "scope": null
- },
- "accesstoken-scope": {
- "access_token": "accesstoken-scope",
- "client_id": "Test Client ID",
- "expires": 99999999900,
- "scope": "testscope"
- },
- "accesstoken-openid-connect": {
- "access_token": "accesstoken-openid-connect",
- "client_id": "Test Client ID",
- "user_id": "testuser",
- "expires": 99999999900,
- "scope": "openid email"
- },
- "accesstoken-malformed": {
- "access_token": "accesstoken-mallformed",
- "expires": 99999999900,
- "scope": "testscope"
- }
- },
- "jwt": {
- "Test Client ID": {
- "key": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5/SxVlE8gnpFqCxgl2wjhzY7u\ncEi00s0kUg3xp7lVEvgLgYcAnHiWp+gtSjOFfH2zsvpiWm6Lz5f743j/FEzHIO1o\nwR0p4d9pOaJK07d01+RzoQLOIQAgXrr4T1CCWUesncwwPBVCyy2Mw3Nmhmr9MrF8\nUlvdRKBxriRnlP3qJQIDAQAB\n-----END PUBLIC KEY-----",
- "subject": "testuser@ourdomain.com"
- },
- "Test Client ID PHP-5.2": {
- "key": "mysecretkey",
- "subject": "testuser@ourdomain.com"
- },
- "Missing Key Client": {
- "key": null,
- "subject": "testuser@ourdomain.com"
- },
- "Missing Key Client PHP-5.2": {
- "key": null,
- "subject": "testuser@ourdomain.com"
- },
- "oauth_test_client": {
- "key": "-----BEGIN CERTIFICATE-----\nMIICiDCCAfGgAwIBAgIBADANBgkqhkiG9w0BAQQFADA9MQswCQYDVQQGEwJVUzEL\nMAkGA1UECBMCVVQxITAfBgNVBAoTGFZpZ25ldHRlIENvcnBvcmF0aW9uIFNCWDAe\nFw0xMTEwMTUwMzE4MjdaFw0zMTEwMTAwMzE4MjdaMD0xCzAJBgNVBAYTAlVTMQsw\nCQYDVQQIEwJVVDEhMB8GA1UEChMYVmlnbmV0dGUgQ29ycG9yYXRpb24gU0JYMIGf\nMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8fpi06NfVYHAOAnxNMVnTXr/ptsLs\nNjP+uAt2eO0cc5J9H5XV8lFVujOrRu/JWi1TDmAvOaf/6A3BphIA1Pwp0AAqlZdw\nizIum8j0KzpsGYH5qReNQDwF3oUSKMsQCCGCDHrDYifG/pRi9bN1ZVjEXPr35HJu\nBe+FQpZTs8DewwIDAQABo4GXMIGUMB0GA1UdDgQWBBRe8hrEXm+Yim4YlD5Nx+1K\nvCYs9DBlBgNVHSMEXjBcgBRe8hrEXm+Yim4YlD5Nx+1KvCYs9KFBpD8wPTELMAkG\nA1UEBhMCVVMxCzAJBgNVBAgTAlVUMSEwHwYDVQQKExhWaWduZXR0ZSBDb3Jwb3Jh\ndGlvbiBTQliCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBjhyRD\nlM7vnLn6drgQVftW5V9nDFAyPAuiGvMIKFSbiAf1PxXCRn5sfJquwWKsJUi4ZGNl\naViXdFmN6/F13PSM+yg63tpKy0fYqMbTM+Oe5WuSHkSW1VuYNHV+24adgNk/FRDL\nFRrlM1f6s9VTLWvwGItjfrof0Ba8Uq7ZDSb9Xg==\n-----END CERTIFICATE-----",
- "subject": "test_subject"
- }
- },
- "jti": [
- {
- "issuer": "Test Client ID",
- "subject": "testuser@ourdomain.com",
- "audience": "http://myapp.com/oauth/auth",
- "expires": 99999999900,
- "jti": "used_jti"
- }
- ],
- "supported_scopes" : [
- "scope1",
- "scope2",
- "scope3",
- "clientscope1",
- "clientscope2",
- "clientscope3",
- "supportedscope1",
- "supportedscope2",
- "supportedscope3",
- "supportedscope4"
- ],
- "keys": {
- "public_key": "-----BEGIN CERTIFICATE-----\nMIICiDCCAfGgAwIBAgIBADANBgkqhkiG9w0BAQQFADA9MQswCQYDVQQGEwJVUzEL\nMAkGA1UECBMCVVQxITAfBgNVBAoTGFZpZ25ldHRlIENvcnBvcmF0aW9uIFNCWDAe\nFw0xMTEwMTUwMzE4MjdaFw0zMTEwMTAwMzE4MjdaMD0xCzAJBgNVBAYTAlVTMQsw\nCQYDVQQIEwJVVDEhMB8GA1UEChMYVmlnbmV0dGUgQ29ycG9yYXRpb24gU0JYMIGf\nMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8fpi06NfVYHAOAnxNMVnTXr/ptsLs\nNjP+uAt2eO0cc5J9H5XV8lFVujOrRu/JWi1TDmAvOaf/6A3BphIA1Pwp0AAqlZdw\nizIum8j0KzpsGYH5qReNQDwF3oUSKMsQCCGCDHrDYifG/pRi9bN1ZVjEXPr35HJu\nBe+FQpZTs8DewwIDAQABo4GXMIGUMB0GA1UdDgQWBBRe8hrEXm+Yim4YlD5Nx+1K\nvCYs9DBlBgNVHSMEXjBcgBRe8hrEXm+Yim4YlD5Nx+1KvCYs9KFBpD8wPTELMAkG\nA1UEBhMCVVMxCzAJBgNVBAgTAlVUMSEwHwYDVQQKExhWaWduZXR0ZSBDb3Jwb3Jh\ndGlvbiBTQliCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBjhyRD\nlM7vnLn6drgQVftW5V9nDFAyPAuiGvMIKFSbiAf1PxXCRn5sfJquwWKsJUi4ZGNl\naViXdFmN6/F13PSM+yg63tpKy0fYqMbTM+Oe5WuSHkSW1VuYNHV+24adgNk/FRDL\nFRrlM1f6s9VTLWvwGItjfrof0Ba8Uq7ZDSb9Xg==\n-----END CERTIFICATE-----",
- "private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIICXQIBAAKBgQC8fpi06NfVYHAOAnxNMVnTXr/ptsLsNjP+uAt2eO0cc5J9H5XV\n8lFVujOrRu/JWi1TDmAvOaf/6A3BphIA1Pwp0AAqlZdwizIum8j0KzpsGYH5qReN\nQDwF3oUSKMsQCCGCDHrDYifG/pRi9bN1ZVjEXPr35HJuBe+FQpZTs8DewwIDAQAB\nAoGARfNxNknmtx/n1bskZ/01iZRzAge6BLEE0LV6Q4gS7mkRZu/Oyiv39Sl5vUlA\n+WdGxLjkBwKNjxGN8Vxw9/ASd8rSsqeAUYIwAeifXrHhj5DBPQT/pDPkeFnp9B1w\nC6jo+3AbBQ4/b0ONSIEnCL2xGGglSIAxO17T1ViXp7lzXPECQQDe63nkRdWM0OCb\noaHQPT3E26224maIstrGFUdt9yw3yJf4bOF7TtiPLlLuHsTTge3z+fG6ntC0xG56\n1cl37C3ZAkEA2HdVcRGugNp/qmVz4LJTpD+WZKi73PLAO47wDOrYh9Pn2I6fcEH0\nCPnggt1ko4ujvGzFTvRH64HXa6aPCv1j+wJBAMQMah3VQPNf/DlDVFEUmw9XeBZg\nVHaifX851aEjgXLp6qVj9IYCmLiLsAmVa9rr6P7p8asD418nZlaHUHE0eDkCQQCr\nuxis6GMx1Ka971jcJX2X696LoxXPd0KsvXySMupv79yagKPa8mgBiwPjrnK+EPVo\ncj6iochA/bSCshP/mwFrAkBHEKPi6V6gb94JinCT7x3weahbdp6bJ6/nzBH/p9VA\nHoT1JtwNFhGv9BCjmDydshQHfSWpY9NxlccBKL7ITm8R\n-----END RSA PRIVATE KEY-----"
- }
-}
diff --git a/library/oauth2/test/lib/OAuth2/Request/TestRequest.php b/library/oauth2/test/lib/OAuth2/Request/TestRequest.php
deleted file mode 100644
index 7bbce28a4..000000000
--- a/library/oauth2/test/lib/OAuth2/Request/TestRequest.php
+++ /dev/null
@@ -1,61 +0,0 @@
-<?php
-
-namespace OAuth2\Request;
-
-use OAuth2\Request;
-use OAuth2\RequestInterface;
-
-/**
-*
-*/
-class TestRequest extends Request implements RequestInterface
-{
- public $query, $request, $server, $headers;
-
- public function __construct()
- {
- $this->query = $_GET;
- $this->request = $_POST;
- $this->server = $_SERVER;
- $this->headers = array();
- }
-
- public function query($name, $default = null)
- {
- return isset($this->query[$name]) ? $this->query[$name] : $default;
- }
-
- public function request($name, $default = null)
- {
- return isset($this->request[$name]) ? $this->request[$name] : $default;
- }
-
- public function server($name, $default = null)
- {
- return isset($this->server[$name]) ? $this->server[$name] : $default;
- }
-
- public function getAllQueryParameters()
- {
- return $this->query;
- }
-
- public function setQuery(array $query)
- {
- $this->query = $query;
- }
-
- public function setPost(array $params)
- {
- $this->server['REQUEST_METHOD'] = 'POST';
- $this->request = $params;
- }
-
- public static function createPost(array $params = array())
- {
- $request = new self();
- $request->setPost($params);
-
- return $request;
- }
-}
diff --git a/library/oauth2/test/lib/OAuth2/Storage/BaseTest.php b/library/oauth2/test/lib/OAuth2/Storage/BaseTest.php
deleted file mode 100755
index 921d52500..000000000
--- a/library/oauth2/test/lib/OAuth2/Storage/BaseTest.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-abstract class BaseTest extends \PHPUnit_Framework_TestCase
-{
- public function provideStorage()
- {
- $memory = Bootstrap::getInstance()->getMemoryStorage();
- $sqlite = Bootstrap::getInstance()->getSqlitePdo();
- $mysql = Bootstrap::getInstance()->getMysqlPdo();
- $postgres = Bootstrap::getInstance()->getPostgresPdo();
- $mongo = Bootstrap::getInstance()->getMongo();
- $redis = Bootstrap::getInstance()->getRedisStorage();
- $cassandra = Bootstrap::getInstance()->getCassandraStorage();
- $dynamodb = Bootstrap::getInstance()->getDynamoDbStorage();
- $couchbase = Bootstrap::getInstance()->getCouchbase();
-
- /* hack until we can fix "default_scope" dependencies in other tests */
- $memory->defaultScope = 'defaultscope1 defaultscope2';
-
- return array(
- array($memory),
- array($sqlite),
- array($mysql),
- array($postgres),
- array($mongo),
- array($redis),
- array($cassandra),
- array($dynamodb),
- array($couchbase),
- );
- }
-}
diff --git a/library/oauth2/test/lib/OAuth2/Storage/Bootstrap.php b/library/oauth2/test/lib/OAuth2/Storage/Bootstrap.php
deleted file mode 100755
index 4ac9022b1..000000000
--- a/library/oauth2/test/lib/OAuth2/Storage/Bootstrap.php
+++ /dev/null
@@ -1,888 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-class Bootstrap
-{
- const DYNAMODB_PHP_VERSION = 'none';
-
- protected static $instance;
- private $mysql;
- private $sqlite;
- private $postgres;
- private $mongo;
- private $redis;
- private $cassandra;
- private $configDir;
- private $dynamodb;
- private $couchbase;
-
- public function __construct()
- {
- $this->configDir = __DIR__.'/../../../config';
- }
-
- public static function getInstance()
- {
- if (!self::$instance) {
- self::$instance = new self();
- }
-
- return self::$instance;
- }
-
- public function getSqlitePdo()
- {
- if (!$this->sqlite) {
- $this->removeSqliteDb();
- $pdo = new \PDO(sprintf('sqlite://%s', $this->getSqliteDir()));
- $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
- $this->createSqliteDb($pdo);
-
- $this->sqlite = new Pdo($pdo);
- }
-
- return $this->sqlite;
- }
-
- public function getPostgresPdo()
- {
- if (!$this->postgres) {
- if (in_array('pgsql', \PDO::getAvailableDrivers())) {
- $this->removePostgresDb();
- $this->createPostgresDb();
- if ($pdo = $this->getPostgresDriver()) {
- $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
- $this->populatePostgresDb($pdo);
- $this->postgres = new Pdo($pdo);
- }
- } else {
- $this->postgres = new NullStorage('Postgres', 'Missing postgres PDO extension.');
- }
- }
-
- return $this->postgres;
- }
-
- public function getPostgresDriver()
- {
- try {
- $pdo = new \PDO('pgsql:host=localhost;dbname=oauth2_server_php', 'postgres');
-
- return $pdo;
- } catch (\PDOException $e) {
- $this->postgres = new NullStorage('Postgres', $e->getMessage());
- }
- }
-
- public function getMemoryStorage()
- {
- return new Memory(json_decode(file_get_contents($this->configDir. '/storage.json'), true));
- }
-
- public function getRedisStorage()
- {
- if (!$this->redis) {
- if (class_exists('Predis\Client')) {
- $redis = new \Predis\Client();
- if ($this->testRedisConnection($redis)) {
- $redis->flushdb();
- $this->redis = new Redis($redis);
- $this->createRedisDb($this->redis);
- } else {
- $this->redis = new NullStorage('Redis', 'Unable to connect to redis server on port 6379');
- }
- } else {
- $this->redis = new NullStorage('Redis', 'Missing redis library. Please run "composer.phar require predis/predis:dev-master"');
- }
- }
-
- return $this->redis;
- }
-
- private function testRedisConnection(\Predis\Client $redis)
- {
- try {
- $redis->connect();
- } catch (\Predis\CommunicationException $exception) {
- // we were unable to connect to the redis server
- return false;
- }
-
- return true;
- }
-
- public function getMysqlPdo()
- {
- if (!$this->mysql) {
- $pdo = null;
- try {
- $pdo = new \PDO('mysql:host=localhost;', 'root');
- } catch (\PDOException $e) {
- $this->mysql = new NullStorage('MySQL', 'Unable to connect to MySQL on root@localhost');
- }
-
- if ($pdo) {
- $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
- $this->removeMysqlDb($pdo);
- $this->createMysqlDb($pdo);
-
- $this->mysql = new Pdo($pdo);
- }
- }
-
- return $this->mysql;
- }
-
- public function getMongo()
- {
- if (!$this->mongo) {
- $skipMongo = $this->getEnvVar('SKIP_MONGO_TESTS');
- if (!$skipMongo && class_exists('MongoClient')) {
- $mongo = new \MongoClient('mongodb://localhost:27017', array('connect' => false));
- if ($this->testMongoConnection($mongo)) {
- $db = $mongo->oauth2_server_php;
- $this->removeMongoDb($db);
- $this->createMongoDb($db);
-
- $this->mongo = new Mongo($db);
- } else {
- $this->mongo = new NullStorage('Mongo', 'Unable to connect to mongo server on "localhost:27017"');
- }
- } else {
- $this->mongo = new NullStorage('Mongo', 'Missing mongo php extension. Please install mongo.so');
- }
- }
-
- return $this->mongo;
- }
-
- private function testMongoConnection(\MongoClient $mongo)
- {
- try {
- $mongo->connect();
- } catch (\MongoConnectionException $e) {
- return false;
- }
-
- return true;
- }
-
- public function getCouchbase()
- {
- if (!$this->couchbase) {
- if ($this->getEnvVar('SKIP_COUCHBASE_TESTS')) {
- $this->couchbase = new NullStorage('Couchbase', 'Skipping Couchbase tests');
- } elseif (!class_exists('Couchbase')) {
- $this->couchbase = new NullStorage('Couchbase', 'Missing Couchbase php extension. Please install couchbase.so');
- } else {
- // round-about way to make sure couchbase is working
- // this is required because it throws a "floating point exception" otherwise
- $code = "new \Couchbase(array('localhost:8091'), '', '', 'auth', false);";
- $exec = sprintf('php -r "%s"', $code);
- $ret = exec($exec, $test, $var);
- if ($ret != 0) {
- $couchbase = new \Couchbase(array('localhost:8091'), '', '', 'auth', false);
- if ($this->testCouchbaseConnection($couchbase)) {
- $this->clearCouchbase($couchbase);
- $this->createCouchbaseDB($couchbase);
-
- $this->couchbase = new CouchbaseDB($couchbase);
- } else {
- $this->couchbase = new NullStorage('Couchbase', 'Unable to connect to Couchbase server on "localhost:8091"');
- }
- } else {
- $this->couchbase = new NullStorage('Couchbase', 'Error while trying to connect to Couchbase');
- }
- }
- }
-
- return $this->couchbase;
- }
-
- private function testCouchbaseConnection(\Couchbase $couchbase)
- {
- try {
- if (count($couchbase->getServers()) > 0) {
- return true;
- }
- } catch (\CouchbaseException $e) {
- return false;
- }
-
- return true;
- }
-
- public function getCassandraStorage()
- {
- if (!$this->cassandra) {
- if (class_exists('phpcassa\ColumnFamily')) {
- $cassandra = new \phpcassa\Connection\ConnectionPool('oauth2_test', array('127.0.0.1:9160'));
- if ($this->testCassandraConnection($cassandra)) {
- $this->removeCassandraDb();
- $this->cassandra = new Cassandra($cassandra);
- $this->createCassandraDb($this->cassandra);
- } else {
- $this->cassandra = new NullStorage('Cassandra', 'Unable to connect to cassandra server on "127.0.0.1:9160"');
- }
- } else {
- $this->cassandra = new NullStorage('Cassandra', 'Missing cassandra library. Please run "composer.phar require thobbs/phpcassa:dev-master"');
- }
- }
-
- return $this->cassandra;
- }
-
- private function testCassandraConnection(\phpcassa\Connection\ConnectionPool $cassandra)
- {
- try {
- new \phpcassa\SystemManager('localhost:9160');
- } catch (\Exception $e) {
- return false;
- }
-
- return true;
- }
-
- private function removeCassandraDb()
- {
- $sys = new \phpcassa\SystemManager('localhost:9160');
-
- try {
- $sys->drop_keyspace('oauth2_test');
- } catch (\cassandra\InvalidRequestException $e) {
-
- }
- }
-
- private function createCassandraDb(Cassandra $storage)
- {
- // create the cassandra keyspace and column family
- $sys = new \phpcassa\SystemManager('localhost:9160');
-
- $sys->create_keyspace('oauth2_test', array(
- "strategy_class" => \phpcassa\Schema\StrategyClass::SIMPLE_STRATEGY,
- "strategy_options" => array('replication_factor' => '1')
- ));
-
- $sys->create_column_family('oauth2_test', 'auth');
- $cassandra = new \phpcassa\Connection\ConnectionPool('oauth2_test', array('127.0.0.1:9160'));
- $cf = new \phpcassa\ColumnFamily($cassandra, 'auth');
-
- // populate the data
- $storage->setClientDetails("oauth_test_client", "testpass", "http://example.com", 'implicit password');
- $storage->setAccessToken("testtoken", "Some Client", '', time() + 1000);
- $storage->setAuthorizationCode("testcode", "Some Client", '', '', time() + 1000);
-
- $storage->setScope('supportedscope1 supportedscope2 supportedscope3 supportedscope4');
- $storage->setScope('defaultscope1 defaultscope2', null, 'default');
-
- $storage->setScope('clientscope1 clientscope2', 'Test Client ID');
- $storage->setScope('clientscope1 clientscope2', 'Test Client ID', 'default');
-
- $storage->setScope('clientscope1 clientscope2 clientscope3', 'Test Client ID 2');
- $storage->setScope('clientscope1 clientscope2', 'Test Client ID 2', 'default');
-
- $storage->setScope('clientscope1 clientscope2', 'Test Default Scope Client ID');
- $storage->setScope('clientscope1 clientscope2', 'Test Default Scope Client ID', 'default');
-
- $storage->setScope('clientscope1 clientscope2 clientscope3', 'Test Default Scope Client ID 2');
- $storage->setScope('clientscope3', 'Test Default Scope Client ID 2', 'default');
-
- $storage->setClientKey('oauth_test_client', $this->getTestPublicKey(), 'test_subject');
-
- $cf->insert("oauth_public_keys:ClientID_One", array('__data' => json_encode(array("public_key" => "client_1_public", "private_key" => "client_1_private", "encryption_algorithm" => "RS256"))));
- $cf->insert("oauth_public_keys:ClientID_Two", array('__data' => json_encode(array("public_key" => "client_2_public", "private_key" => "client_2_private", "encryption_algorithm" => "RS256"))));
- $cf->insert("oauth_public_keys:", array('__data' => json_encode(array("public_key" => $this->getTestPublicKey(), "private_key" => $this->getTestPrivateKey(), "encryption_algorithm" => "RS256"))));
-
- $cf->insert("oauth_users:testuser", array('__data' =>json_encode(array("password" => "password", "email" => "testuser@test.com", "email_verified" => true))));
-
- }
-
- private function createSqliteDb(\PDO $pdo)
- {
- $this->runPdoSql($pdo);
- }
-
- private function removeSqliteDb()
- {
- if (file_exists($this->getSqliteDir())) {
- unlink($this->getSqliteDir());
- }
- }
-
- private function createMysqlDb(\PDO $pdo)
- {
- $pdo->exec('CREATE DATABASE oauth2_server_php');
- $pdo->exec('USE oauth2_server_php');
- $this->runPdoSql($pdo);
- }
-
- private function removeMysqlDb(\PDO $pdo)
- {
- $pdo->exec('DROP DATABASE IF EXISTS oauth2_server_php');
- }
-
- private function createPostgresDb()
- {
- if (!`psql postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='postgres'"`) {
- `createuser -s -r postgres`;
- }
-
- `createdb -O postgres oauth2_server_php`;
- }
-
- private function populatePostgresDb(\PDO $pdo)
- {
- $this->runPdoSql($pdo);
- }
-
- private function removePostgresDb()
- {
- if (trim(`psql -l | grep oauth2_server_php | wc -l`)) {
- `dropdb oauth2_server_php`;
- }
- }
-
- public function runPdoSql(\PDO $pdo)
- {
- $storage = new Pdo($pdo);
- foreach (explode(';', $storage->getBuildSql()) as $statement) {
- $result = $pdo->exec($statement);
- }
-
- // set up scopes
- $sql = 'INSERT INTO oauth_scopes (scope) VALUES (?)';
- foreach (explode(' ', 'supportedscope1 supportedscope2 supportedscope3 supportedscope4 clientscope1 clientscope2 clientscope3') as $supportedScope) {
- $pdo->prepare($sql)->execute(array($supportedScope));
- }
-
- $sql = 'INSERT INTO oauth_scopes (scope, is_default) VALUES (?, ?)';
- foreach (array('defaultscope1', 'defaultscope2') as $defaultScope) {
- $pdo->prepare($sql)->execute(array($defaultScope, true));
- }
-
- // set up clients
- $sql = 'INSERT INTO oauth_clients (client_id, client_secret, scope, grant_types) VALUES (?, ?, ?, ?)';
- $pdo->prepare($sql)->execute(array('Test Client ID', 'TestSecret', 'clientscope1 clientscope2', null));
- $pdo->prepare($sql)->execute(array('Test Client ID 2', 'TestSecret', 'clientscope1 clientscope2 clientscope3', null));
- $pdo->prepare($sql)->execute(array('Test Default Scope Client ID', 'TestSecret', 'clientscope1 clientscope2', null));
- $pdo->prepare($sql)->execute(array('oauth_test_client', 'testpass', null, 'implicit password'));
-
- // set up misc
- $sql = 'INSERT INTO oauth_access_tokens (access_token, client_id, expires, user_id) VALUES (?, ?, ?, ?)';
- $pdo->prepare($sql)->execute(array('testtoken', 'Some Client', date('Y-m-d H:i:s', strtotime('+1 hour')), null));
- $pdo->prepare($sql)->execute(array('accesstoken-openid-connect', 'Some Client', date('Y-m-d H:i:s', strtotime('+1 hour')), 'testuser'));
-
- $sql = 'INSERT INTO oauth_authorization_codes (authorization_code, client_id, expires) VALUES (?, ?, ?)';
- $pdo->prepare($sql)->execute(array('testcode', 'Some Client', date('Y-m-d H:i:s', strtotime('+1 hour'))));
-
- $sql = 'INSERT INTO oauth_users (username, password, email, email_verified) VALUES (?, ?, ?, ?)';
- $pdo->prepare($sql)->execute(array('testuser', 'password', 'testuser@test.com', true));
-
- $sql = 'INSERT INTO oauth_public_keys (client_id, public_key, private_key, encryption_algorithm) VALUES (?, ?, ?, ?)';
- $pdo->prepare($sql)->execute(array('ClientID_One', 'client_1_public', 'client_1_private', 'RS256'));
- $pdo->prepare($sql)->execute(array('ClientID_Two', 'client_2_public', 'client_2_private', 'RS256'));
-
- $sql = 'INSERT INTO oauth_public_keys (client_id, public_key, private_key, encryption_algorithm) VALUES (?, ?, ?, ?)';
- $pdo->prepare($sql)->execute(array(null, $this->getTestPublicKey(), $this->getTestPrivateKey(), 'RS256'));
-
- $sql = 'INSERT INTO oauth_jwt (client_id, subject, public_key) VALUES (?, ?, ?)';
- $pdo->prepare($sql)->execute(array('oauth_test_client', 'test_subject', $this->getTestPublicKey()));
- }
-
- public function getSqliteDir()
- {
- return $this->configDir. '/test.sqlite';
- }
-
- public function getConfigDir()
- {
- return $this->configDir;
- }
-
- private function createCouchbaseDB(\Couchbase $db)
- {
- $db->set('oauth_clients-oauth_test_client',json_encode(array(
- 'client_id' => "oauth_test_client",
- 'client_secret' => "testpass",
- 'redirect_uri' => "http://example.com",
- 'grant_types' => 'implicit password'
- )));
-
- $db->set('oauth_access_tokens-testtoken',json_encode(array(
- 'access_token' => "testtoken",
- 'client_id' => "Some Client"
- )));
-
- $db->set('oauth_authorization_codes-testcode',json_encode(array(
- 'access_token' => "testcode",
- 'client_id' => "Some Client"
- )));
-
- $db->set('oauth_users-testuser',json_encode(array(
- 'username' => 'testuser',
- 'password' => 'password',
- 'email' => 'testuser@test.com',
- 'email_verified' => true,
- )));
-
- $db->set('oauth_jwt-oauth_test_client',json_encode(array(
- 'client_id' => 'oauth_test_client',
- 'key' => $this->getTestPublicKey(),
- 'subject' => 'test_subject',
- )));
- }
-
- private function clearCouchbase(\Couchbase $cb)
- {
- $cb->delete('oauth_authorization_codes-new-openid-code');
- $cb->delete('oauth_access_tokens-newtoken');
- $cb->delete('oauth_authorization_codes-newcode');
- $cb->delete('oauth_refresh_tokens-refreshtoken');
- }
-
- private function createMongoDb(\MongoDB $db)
- {
- $db->oauth_clients->insert(array(
- 'client_id' => "oauth_test_client",
- 'client_secret' => "testpass",
- 'redirect_uri' => "http://example.com",
- 'grant_types' => 'implicit password'
- ));
-
- $db->oauth_access_tokens->insert(array(
- 'access_token' => "testtoken",
- 'client_id' => "Some Client"
- ));
-
- $db->oauth_authorization_codes->insert(array(
- 'authorization_code' => "testcode",
- 'client_id' => "Some Client"
- ));
-
- $db->oauth_users->insert(array(
- 'username' => 'testuser',
- 'password' => 'password',
- 'email' => 'testuser@test.com',
- 'email_verified' => true,
- ));
-
- $db->oauth_jwt->insert(array(
- 'client_id' => 'oauth_test_client',
- 'key' => $this->getTestPublicKey(),
- 'subject' => 'test_subject',
- ));
- }
-
- private function createRedisDb(Redis $storage)
- {
- $storage->setClientDetails("oauth_test_client", "testpass", "http://example.com", 'implicit password');
- $storage->setAccessToken("testtoken", "Some Client", '', time() + 1000);
- $storage->setAuthorizationCode("testcode", "Some Client", '', '', time() + 1000);
- $storage->setUser("testuser", "password");
-
- $storage->setScope('supportedscope1 supportedscope2 supportedscope3 supportedscope4');
- $storage->setScope('defaultscope1 defaultscope2', null, 'default');
-
- $storage->setScope('clientscope1 clientscope2', 'Test Client ID');
- $storage->setScope('clientscope1 clientscope2', 'Test Client ID', 'default');
-
- $storage->setScope('clientscope1 clientscope2 clientscope3', 'Test Client ID 2');
- $storage->setScope('clientscope1 clientscope2', 'Test Client ID 2', 'default');
-
- $storage->setScope('clientscope1 clientscope2', 'Test Default Scope Client ID');
- $storage->setScope('clientscope1 clientscope2', 'Test Default Scope Client ID', 'default');
-
- $storage->setScope('clientscope1 clientscope2 clientscope3', 'Test Default Scope Client ID 2');
- $storage->setScope('clientscope3', 'Test Default Scope Client ID 2', 'default');
-
- $storage->setClientKey('oauth_test_client', $this->getTestPublicKey(), 'test_subject');
- }
-
- public function removeMongoDb(\MongoDB $db)
- {
- $db->drop();
- }
-
- public function getTestPublicKey()
- {
- return file_get_contents(__DIR__.'/../../../config/keys/id_rsa.pub');
- }
-
- private function getTestPrivateKey()
- {
- return file_get_contents(__DIR__.'/../../../config/keys/id_rsa');
- }
-
- public function getDynamoDbStorage()
- {
- if (!$this->dynamodb) {
- // only run once per travis build
- if (true == $this->getEnvVar('TRAVIS')) {
- if (self::DYNAMODB_PHP_VERSION != $this->getEnvVar('TRAVIS_PHP_VERSION')) {
- $this->dynamodb = new NullStorage('DynamoDb', 'Skipping for travis.ci - only run once per build');
-
- return;
- }
- }
- if (class_exists('\Aws\DynamoDb\DynamoDbClient')) {
- if ($client = $this->getDynamoDbClient()) {
- // travis runs a unique set of tables per build, to avoid conflict
- $prefix = '';
- if ($build_id = $this->getEnvVar('TRAVIS_JOB_NUMBER')) {
- $prefix = sprintf('build_%s_', $build_id);
- } else {
- if (!$this->deleteDynamoDb($client, $prefix, true)) {
- return $this->dynamodb = new NullStorage('DynamoDb', 'Timed out while waiting for DynamoDB deletion (30 seconds)');
- }
- }
- $this->createDynamoDb($client, $prefix);
- $this->populateDynamoDb($client, $prefix);
- $config = array(
- 'client_table' => $prefix.'oauth_clients',
- 'access_token_table' => $prefix.'oauth_access_tokens',
- 'refresh_token_table' => $prefix.'oauth_refresh_tokens',
- 'code_table' => $prefix.'oauth_authorization_codes',
- 'user_table' => $prefix.'oauth_users',
- 'jwt_table' => $prefix.'oauth_jwt',
- 'scope_table' => $prefix.'oauth_scopes',
- 'public_key_table' => $prefix.'oauth_public_keys',
- );
- $this->dynamodb = new DynamoDB($client, $config);
- } elseif (!$this->dynamodb) {
- $this->dynamodb = new NullStorage('DynamoDb', 'unable to connect to DynamoDB');
- }
- } else {
- $this->dynamodb = new NullStorage('DynamoDb', 'Missing DynamoDB library. Please run "composer.phar require aws/aws-sdk-php:dev-master');
- }
- }
-
- return $this->dynamodb;
- }
-
- private function getDynamoDbClient()
- {
- $config = array();
- // check for environment variables
- if (($key = $this->getEnvVar('AWS_ACCESS_KEY_ID')) && ($secret = $this->getEnvVar('AWS_SECRET_KEY'))) {
- $config['key'] = $key;
- $config['secret'] = $secret;
- } else {
- // fall back on ~/.aws/credentials file
- // @see http://docs.aws.amazon.com/aws-sdk-php/guide/latest/credentials.html#credential-profiles
- if (!file_exists($this->getEnvVar('HOME') . '/.aws/credentials')) {
- $this->dynamodb = new NullStorage('DynamoDb', 'No aws credentials file found, and no AWS_ACCESS_KEY_ID or AWS_SECRET_KEY environment variable set');
-
- return;
- }
-
- // set profile in AWS_PROFILE environment variable, defaults to "default"
- $config['profile'] = $this->getEnvVar('AWS_PROFILE', 'default');
- }
-
- // set region in AWS_REGION environment variable, defaults to "us-east-1"
- $config['region'] = $this->getEnvVar('AWS_REGION', \Aws\Common\Enum\Region::US_EAST_1);
-
- return \Aws\DynamoDb\DynamoDbClient::factory($config);
- }
-
- private function deleteDynamoDb(\Aws\DynamoDb\DynamoDbClient $client, $prefix = null, $waitForDeletion = false)
- {
- $tablesList = explode(' ', 'oauth_access_tokens oauth_authorization_codes oauth_clients oauth_jwt oauth_public_keys oauth_refresh_tokens oauth_scopes oauth_users');
- $nbTables = count($tablesList);
-
- // Delete all table.
- foreach ($tablesList as $key => $table) {
- try {
- $client->deleteTable(array('TableName' => $prefix.$table));
- } catch (\Aws\DynamoDb\Exception\DynamoDbException $e) {
- // Table does not exist : nothing to do
- }
- }
-
- // Wait for deleting
- if ($waitForDeletion) {
- $retries = 5;
- $nbTableDeleted = 0;
- while ($nbTableDeleted != $nbTables) {
- $nbTableDeleted = 0;
- foreach ($tablesList as $key => $table) {
- try {
- $result = $client->describeTable(array('TableName' => $prefix.$table));
- } catch (\Aws\DynamoDb\Exception\DynamoDbException $e) {
- // Table does not exist : nothing to do
- $nbTableDeleted++;
- }
- }
- if ($nbTableDeleted != $nbTables) {
- if ($retries < 0) {
- // we are tired of waiting
- return false;
- }
- sleep(5);
- echo "Sleeping 5 seconds for DynamoDB ($retries more retries)...\n";
- $retries--;
- }
- }
- }
-
- return true;
- }
-
- private function createDynamoDb(\Aws\DynamoDb\DynamoDbClient $client, $prefix = null)
- {
- $tablesList = explode(' ', 'oauth_access_tokens oauth_authorization_codes oauth_clients oauth_jwt oauth_public_keys oauth_refresh_tokens oauth_scopes oauth_users');
- $nbTables = count($tablesList);
- $client->createTable(array(
- 'TableName' => $prefix.'oauth_access_tokens',
- 'AttributeDefinitions' => array(
- array('AttributeName' => 'access_token','AttributeType' => 'S')
- ),
- 'KeySchema' => array(array('AttributeName' => 'access_token','KeyType' => 'HASH')),
- 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1)
- ));
-
- $client->createTable(array(
- 'TableName' => $prefix.'oauth_authorization_codes',
- 'AttributeDefinitions' => array(
- array('AttributeName' => 'authorization_code','AttributeType' => 'S')
- ),
- 'KeySchema' => array(array('AttributeName' => 'authorization_code','KeyType' => 'HASH')),
- 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1)
- ));
-
- $client->createTable(array(
- 'TableName' => $prefix.'oauth_clients',
- 'AttributeDefinitions' => array(
- array('AttributeName' => 'client_id','AttributeType' => 'S')
- ),
- 'KeySchema' => array(array('AttributeName' => 'client_id','KeyType' => 'HASH')),
- 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1)
- ));
-
- $client->createTable(array(
- 'TableName' => $prefix.'oauth_jwt',
- 'AttributeDefinitions' => array(
- array('AttributeName' => 'client_id','AttributeType' => 'S'),
- array('AttributeName' => 'subject','AttributeType' => 'S')
- ),
- 'KeySchema' => array(
- array('AttributeName' => 'client_id','KeyType' => 'HASH'),
- array('AttributeName' => 'subject','KeyType' => 'RANGE')
- ),
- 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1)
- ));
-
- $client->createTable(array(
- 'TableName' => $prefix.'oauth_public_keys',
- 'AttributeDefinitions' => array(
- array('AttributeName' => 'client_id','AttributeType' => 'S')
- ),
- 'KeySchema' => array(array('AttributeName' => 'client_id','KeyType' => 'HASH')),
- 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1)
- ));
-
- $client->createTable(array(
- 'TableName' => $prefix.'oauth_refresh_tokens',
- 'AttributeDefinitions' => array(
- array('AttributeName' => 'refresh_token','AttributeType' => 'S')
- ),
- 'KeySchema' => array(array('AttributeName' => 'refresh_token','KeyType' => 'HASH')),
- 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1)
- ));
-
- $client->createTable(array(
- 'TableName' => $prefix.'oauth_scopes',
- 'AttributeDefinitions' => array(
- array('AttributeName' => 'scope','AttributeType' => 'S'),
- array('AttributeName' => 'is_default','AttributeType' => 'S')
- ),
- 'KeySchema' => array(array('AttributeName' => 'scope','KeyType' => 'HASH')),
- 'GlobalSecondaryIndexes' => array(
- array(
- 'IndexName' => 'is_default-index',
- 'KeySchema' => array(array('AttributeName' => 'is_default', 'KeyType' => 'HASH')),
- 'Projection' => array('ProjectionType' => 'ALL'),
- 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1)
- ),
- ),
- 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1)
- ));
-
- $client->createTable(array(
- 'TableName' => $prefix.'oauth_users',
- 'AttributeDefinitions' => array(array('AttributeName' => 'username','AttributeType' => 'S')),
- 'KeySchema' => array(array('AttributeName' => 'username','KeyType' => 'HASH')),
- 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1)
- ));
-
- // Wait for creation
- $nbTableCreated = 0;
- while ($nbTableCreated != $nbTables) {
- $nbTableCreated = 0;
- foreach ($tablesList as $key => $table) {
- try {
- $result = $client->describeTable(array('TableName' => $prefix.$table));
- if ($result['Table']['TableStatus'] == 'ACTIVE') {
- $nbTableCreated++;
- }
- } catch (\Aws\DynamoDb\Exception\DynamoDbException $e) {
- // Table does not exist : nothing to do
- $nbTableCreated++;
- }
- }
- if ($nbTableCreated != $nbTables) {
- sleep(1);
- }
- }
- }
-
- private function populateDynamoDb($client, $prefix = null)
- {
- // set up scopes
- foreach (explode(' ', 'supportedscope1 supportedscope2 supportedscope3 supportedscope4 clientscope1 clientscope2 clientscope3') as $supportedScope) {
- $client->putItem(array(
- 'TableName' => $prefix.'oauth_scopes',
- 'Item' => array('scope' => array('S' => $supportedScope))
- ));
- }
-
- foreach (array('defaultscope1', 'defaultscope2') as $defaultScope) {
- $client->putItem(array(
- 'TableName' => $prefix.'oauth_scopes',
- 'Item' => array('scope' => array('S' => $defaultScope), 'is_default' => array('S' => "true"))
- ));
- }
-
- $client->putItem(array(
- 'TableName' => $prefix.'oauth_clients',
- 'Item' => array(
- 'client_id' => array('S' => 'Test Client ID'),
- 'client_secret' => array('S' => 'TestSecret'),
- 'scope' => array('S' => 'clientscope1 clientscope2')
- )
- ));
-
- $client->putItem(array(
- 'TableName' => $prefix.'oauth_clients',
- 'Item' => array(
- 'client_id' => array('S' => 'Test Client ID 2'),
- 'client_secret' => array('S' => 'TestSecret'),
- 'scope' => array('S' => 'clientscope1 clientscope2 clientscope3')
- )
- ));
-
- $client->putItem(array(
- 'TableName' => $prefix.'oauth_clients',
- 'Item' => array(
- 'client_id' => array('S' => 'Test Default Scope Client ID'),
- 'client_secret' => array('S' => 'TestSecret'),
- 'scope' => array('S' => 'clientscope1 clientscope2')
- )
- ));
-
- $client->putItem(array(
- 'TableName' => $prefix.'oauth_clients',
- 'Item' => array(
- 'client_id' => array('S' => 'oauth_test_client'),
- 'client_secret' => array('S' => 'testpass'),
- 'grant_types' => array('S' => 'implicit password')
- )
- ));
-
- $client->putItem(array(
- 'TableName' => $prefix.'oauth_access_tokens',
- 'Item' => array(
- 'access_token' => array('S' => 'testtoken'),
- 'client_id' => array('S' => 'Some Client'),
- )
- ));
-
- $client->putItem(array(
- 'TableName' => $prefix.'oauth_access_tokens',
- 'Item' => array(
- 'access_token' => array('S' => 'accesstoken-openid-connect'),
- 'client_id' => array('S' => 'Some Client'),
- 'user_id' => array('S' => 'testuser'),
- )
- ));
-
- $client->putItem(array(
- 'TableName' => $prefix.'oauth_authorization_codes',
- 'Item' => array(
- 'authorization_code' => array('S' => 'testcode'),
- 'client_id' => array('S' => 'Some Client'),
- )
- ));
-
- $client->putItem(array(
- 'TableName' => $prefix.'oauth_users',
- 'Item' => array(
- 'username' => array('S' => 'testuser'),
- 'password' => array('S' => 'password'),
- 'email' => array('S' => 'testuser@test.com'),
- 'email_verified' => array('S' => 'true'),
- )
- ));
-
- $client->putItem(array(
- 'TableName' => $prefix.'oauth_public_keys',
- 'Item' => array(
- 'client_id' => array('S' => 'ClientID_One'),
- 'public_key' => array('S' => 'client_1_public'),
- 'private_key' => array('S' => 'client_1_private'),
- 'encryption_algorithm' => array('S' => 'RS256'),
- )
- ));
-
- $client->putItem(array(
- 'TableName' => $prefix.'oauth_public_keys',
- 'Item' => array(
- 'client_id' => array('S' => 'ClientID_Two'),
- 'public_key' => array('S' => 'client_2_public'),
- 'private_key' => array('S' => 'client_2_private'),
- 'encryption_algorithm' => array('S' => 'RS256'),
- )
- ));
-
- $client->putItem(array(
- 'TableName' => $prefix.'oauth_public_keys',
- 'Item' => array(
- 'client_id' => array('S' => '0'),
- 'public_key' => array('S' => $this->getTestPublicKey()),
- 'private_key' => array('S' => $this->getTestPrivateKey()),
- 'encryption_algorithm' => array('S' => 'RS256'),
- )
- ));
-
- $client->putItem(array(
- 'TableName' => $prefix.'oauth_jwt',
- 'Item' => array(
- 'client_id' => array('S' => 'oauth_test_client'),
- 'subject' => array('S' => 'test_subject'),
- 'public_key' => array('S' => $this->getTestPublicKey()),
- )
- ));
- }
-
- public function cleanupTravisDynamoDb($prefix = null)
- {
- if (is_null($prefix)) {
- // skip this when not applicable
- if (!$this->getEnvVar('TRAVIS') || self::DYNAMODB_PHP_VERSION != $this->getEnvVar('TRAVIS_PHP_VERSION')) {
- return;
- }
-
- $prefix = sprintf('build_%s_', $this->getEnvVar('TRAVIS_JOB_NUMBER'));
- }
-
- $client = $this->getDynamoDbClient();
- $this->deleteDynamoDb($client, $prefix);
- }
-
- private function getEnvVar($var, $default = null)
- {
- return isset($_SERVER[$var]) ? $_SERVER[$var] : (getenv($var) ?: $default);
- }
-}
diff --git a/library/oauth2/test/lib/OAuth2/Storage/NullStorage.php b/library/oauth2/test/lib/OAuth2/Storage/NullStorage.php
deleted file mode 100644
index 6caa62068..000000000
--- a/library/oauth2/test/lib/OAuth2/Storage/NullStorage.php
+++ /dev/null
@@ -1,32 +0,0 @@
-<?php
-
-namespace OAuth2\Storage;
-
-/**
-*
-*/
-class NullStorage extends Memory
-{
- private $name;
- private $description;
-
- public function __construct($name, $description = null)
- {
- $this->name = $name;
- $this->description = $description;
- }
-
- public function __toString()
- {
- return $this->name;
- }
-
- public function getMessage()
- {
- if ($this->description) {
- return $this->description;
- }
-
- return $this->name;
- }
-}