From c82f910da318491b70f5bb39e88adb0e1f8238e1 Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Sun, 8 Jul 2018 17:02:28 +0200 Subject: [PATCH 1/5] Refactor configuration to remove optional sections from minimal template Also move tests from dedicated directory to source dir with .spec.ts extension --- .travis.yml | 2 - Gruntfile.js | 6 +- config.minimal.yml | 24 +++ config.template.yml | 5 +- .../src/lib/AuthenticationSessionHandler.ts | 2 +- .../lib/IdentityCheckMiddleware.spec.ts} | 63 +++--- server/src/lib/IdentityCheckMiddleware.ts | 25 +-- server/src/lib/IdentityValidable.ts | 19 ++ server/src/lib/IdentityValidableStub.spec.ts | 52 +++++ .../lib/Server.spec.ts} | 12 +- server/src/lib/Server.ts | 41 ++-- server/src/lib/ServerVariables.ts | 4 +- server/src/lib/ServerVariablesInitializer.ts | 6 +- .../lib/ServerVariablesMockBuilder.spec.ts} | 31 +-- .../access_control/AccessController.spec.ts} | 6 +- .../lib/access_control/AccessController.ts | 2 +- .../AccessControllerStub.spec.ts} | 3 +- .../authentication/MethodCalculator.spec.ts} | 7 +- .../lib/authentication/MethodCalculator.ts | 2 +- .../authentication/totp/TotpHandler.spec.ts} | 4 +- .../totp/TotpHandlerStub.spec.ts} | 4 +- .../u2f/U2fHandlerStub.spec.ts} | 2 +- .../src/lib/configuration/Configuration.d.ts | 155 --------------- .../ConfigurationParser.spec.ts} | 18 +- .../lib/configuration/ConfigurationParser.ts | 124 +++--------- .../SessionConfigurationBuilder.spec.ts} | 22 ++- .../SessionConfigurationBuilder.ts | 4 +- server/src/lib/configuration/Validator.ts | 94 --------- .../lib/configuration/adapters/ACLAdapter.ts | 39 ---- .../adapters/AuthenticationMethodsAdapter.ts | 30 --- .../lib/configuration/adapters/TOTPAdapter.ts | 20 -- .../schema/AclConfiguration.spec.ts | 14 ++ .../configuration/schema/AclConfiguration.ts | 42 ++++ ...AuthenticationMethodsConfiguration.spec.ts | 12 ++ .../AuthenticationMethodsConfiguration.ts | 21 ++ .../lib/configuration/schema/Configuration.ts | 55 ++++++ .../schema/LdapConfiguration.spec.ts | 25 +++ .../configuration/schema/LdapConfiguration.ts | 40 ++++ .../schema/NotifierConfiguration.spec.ts | 31 +++ .../schema/NotifierConfiguration.ts | 42 ++++ .../schema/RegulationConfiguration.spec.ts | 13 ++ .../schema/RegulationConfiguration.ts | 23 +++ .../schema/SessionConfiguration.spec.ts | 15 ++ .../schema/SessionConfiguration.ts | 26 +++ .../schema/StorageConfiguration.spec.ts | 15 ++ .../schema/StorageConfiguration.ts | 25 +++ .../configuration/schema/TotpConfiguration.ts | 13 ++ .../schema/UserDatabaseConfiguration.ts | 9 + .../lib/connectors/mongo/MongoClient.spec.ts} | 4 +- .../connectors/mongo/MongoClientStub.spec.ts} | 0 .../connectors/mongo/MongoConnector.spec.ts} | 6 +- .../mongo/MongoConnectorFactory.spec.ts} | 4 +- .../lib/ldap/Authenticator.spec.ts} | 15 +- server/src/lib/ldap/Authenticator.ts | 2 +- .../lib/ldap/AuthenticatorStub.spec.ts} | 2 +- .../lib/ldap/Client.spec.ts} | 25 +-- server/src/lib/ldap/Client.ts | 17 +- server/src/lib/ldap/ClientFactory.ts | 2 +- .../lib/ldap/ClientFactoryStub.spec.ts} | 0 .../lib/ldap/ClientStub.spec.ts} | 2 +- .../src/lib/ldap/EmailsAndGroupsRetriever.ts | 2 +- .../lib/ldap/EmailsRetriever.spec.ts} | 15 +- server/src/lib/ldap/EmailsRetriever.ts | 2 +- .../lib/ldap/EmailsRetrieverStub.spec.ts} | 4 +- .../lib/ldap/InputsSanitizer.spec.ts} | 4 +- server/src/lib/ldap/LdapClientFactory.ts | 2 +- .../lib/ldap/LdapClientFactoryStub.spec.ts} | 4 +- .../lib/ldap/LdapClientStub.spec.ts} | 2 +- .../lib/ldap/PasswordUpdater.spec.ts} | 17 +- server/src/lib/ldap/PasswordUpdater.ts | 2 +- .../lib/ldap/PasswordUpdaterStub.spec.ts} | 4 +- .../lib/ldap/SanitizedClient.spec.ts} | 6 +- .../lib/logging/RequestLoggerStub.spec.ts} | 4 +- .../lib/notifiers/EmailNotifier.spec.ts} | 10 +- .../{EMailNotifier.ts => EmailNotifier.ts} | 4 +- .../src/lib/notifiers/FileSystemNotifier.ts | 2 +- .../src/lib/notifiers/IMailSenderBuilder.ts | 2 +- .../lib/notifiers/MailSenderBuilder.spec.ts} | 4 +- server/src/lib/notifiers/MailSenderBuilder.ts | 2 +- .../notifiers/MailSenderBuilderStub.spec.ts} | 2 +- .../lib/notifiers/MailSenderStub.spec.ts} | 0 .../lib/notifiers/NotifierFactory.spec.ts} | 12 +- server/src/lib/notifiers/NotifierFactory.ts | 6 +- .../lib/notifiers/NotifierStub.spec.ts} | 2 +- server/src/lib/notifiers/SmtpNotifier.ts | 2 +- .../lib/regulation/Regulator.spec.ts} | 8 +- .../src/lib/regulation/RegulatorStub.spec.ts | 22 +++ .../lib/routes/error/401/get.spec.ts} | 8 +- .../lib/routes/error/403/get.spec.ts} | 8 +- .../lib/routes/error/404/get.spec.ts} | 4 +- .../lib/routes/firstfactor/post.spec.ts} | 22 +-- .../routes/password-reset/form/post.spec.ts} | 23 +-- .../identity/PasswordResetHandler.spec.ts} | 14 +- .../identity/PasswordResetHandler.ts | 2 +- .../lib/routes/secondfactor/get.spec.ts} | 12 +- .../lib/routes/secondfactor/redirect.spec.ts} | 10 +- .../identity/RegistrationHandler.spec.ts} | 14 +- .../totp/identity/RegistrationHandler.ts | 8 +- .../secondfactor/totp/sign/post.spec.ts} | 18 +- .../lib/routes/secondfactor/totp/sign/post.ts | 18 +- .../u2f/identity/RegistrationHandler.spec.ts} | 14 +- .../u2f/identity/RegistrationHandler.ts | 2 +- .../secondfactor/u2f/register/post.spec.ts} | 16 +- .../u2f/register_request/get.spec.ts} | 12 +- .../secondfactor/u2f/sign/post.spec.ts} | 12 +- .../u2f/sign_request/get.spec.ts} | 16 +- .../lib/routes/verify/get.spec.ts} | 15 +- .../lib/routes/verify/get_session_cookie.ts | 4 +- .../storage/CollectionFactoryStub.spec.ts} | 4 +- .../lib/storage/CollectionStub.spec.ts} | 2 +- .../lib/storage/UserDataStore.spec.ts} | 14 +- .../lib/storage/UserDataStoreStub.spec.ts} | 11 +- .../storage/mongo/MongoCollection.spec.ts} | 6 +- .../mongo/MongoCollectionFactory.spec.ts} | 6 +- .../lib/storage/nedb/NedbCollection.spec.ts} | 4 +- .../nedb/NedbCollectionFactory.spec.ts} | 4 +- .../lib/stubs/express.spec.ts} | 0 .../lib/stubs/ldapjs.spec.ts} | 0 .../lib/stubs/speakeasy.spec.ts} | 0 .../u2f.ts => src/lib/stubs/u2f.spec.ts} | 0 .../lib/utils/DomainExtractor.spec.ts} | 4 +- .../lib/utils/HashGenerator.spec.ts} | 4 +- server/src/lib/web_server/Configurator.ts | 4 +- .../middlewares/RequireTwoFactorEnabled.ts | 2 +- .../LdapConfigurationAdaptation.test.ts | 100 ---------- server/test/configuration/Validator.test.ts | 187 ------------------ .../configuration/adapters/ACLAdapter.test.ts | 162 --------------- .../AuthenticationMethodsAdapter.test.ts | 59 ------ server/test/mocks/AuthenticationRegulator.ts | 15 -- server/test/mocks/IdentityValidator.ts | 39 ---- server/test/mocks/Notifier.ts | 12 -- server/test/mocks/RegulatorStub.ts | 21 -- server/test/mocks/TOTPValidator.ts | 12 -- server/tsconfig.json | 5 +- .../step_definitions/authentication.ts | 4 +- test/features/support/world.ts | 8 +- 136 files changed, 951 insertions(+), 1464 deletions(-) create mode 100644 config.minimal.yml rename server/{test/IdentityCheckMiddleware.test.ts => src/lib/IdentityCheckMiddleware.spec.ts} (73%) create mode 100644 server/src/lib/IdentityValidable.ts create mode 100644 server/src/lib/IdentityValidableStub.spec.ts rename server/{test/ServerConfiguration.test.ts => src/lib/Server.spec.ts} (82%) rename server/{test/mocks/ServerVariablesMockBuilder.ts => src/lib/ServerVariablesMockBuilder.spec.ts} (70%) rename server/{test/access_control/AccessController.test.ts => src/lib/access_control/AccessController.spec.ts} (98%) rename server/{test/mocks/AccessControllerStub.ts => src/lib/access_control/AccessControllerStub.spec.ts} (81%) rename server/{test/authentication/MethodCalculator.test.ts => src/lib/authentication/MethodCalculator.spec.ts} (93%) rename server/{test/authentication/totp/Validator.test.ts => src/lib/authentication/totp/TotpHandler.spec.ts} (88%) rename server/{test/mocks/TotpHandlerStub.ts => src/lib/authentication/totp/TotpHandlerStub.spec.ts} (79%) rename server/{test/mocks/U2fHandlerStub.ts => src/lib/authentication/u2f/U2fHandlerStub.spec.ts} (92%) delete mode 100644 server/src/lib/configuration/Configuration.d.ts rename server/{test/configuration/ConfigurationParser.test.ts => src/lib/configuration/ConfigurationParser.spec.ts} (92%) rename server/{test/SessionConfigurationBuilder.test.ts => src/lib/configuration/SessionConfigurationBuilder.spec.ts} (87%) delete mode 100644 server/src/lib/configuration/Validator.ts delete mode 100644 server/src/lib/configuration/adapters/ACLAdapter.ts delete mode 100644 server/src/lib/configuration/adapters/AuthenticationMethodsAdapter.ts delete mode 100644 server/src/lib/configuration/adapters/TOTPAdapter.ts create mode 100644 server/src/lib/configuration/schema/AclConfiguration.spec.ts create mode 100644 server/src/lib/configuration/schema/AclConfiguration.ts create mode 100644 server/src/lib/configuration/schema/AuthenticationMethodsConfiguration.spec.ts create mode 100644 server/src/lib/configuration/schema/AuthenticationMethodsConfiguration.ts create mode 100644 server/src/lib/configuration/schema/Configuration.ts create mode 100644 server/src/lib/configuration/schema/LdapConfiguration.spec.ts create mode 100644 server/src/lib/configuration/schema/LdapConfiguration.ts create mode 100644 server/src/lib/configuration/schema/NotifierConfiguration.spec.ts create mode 100644 server/src/lib/configuration/schema/NotifierConfiguration.ts create mode 100644 server/src/lib/configuration/schema/RegulationConfiguration.spec.ts create mode 100644 server/src/lib/configuration/schema/RegulationConfiguration.ts create mode 100644 server/src/lib/configuration/schema/SessionConfiguration.spec.ts create mode 100644 server/src/lib/configuration/schema/SessionConfiguration.ts create mode 100644 server/src/lib/configuration/schema/StorageConfiguration.spec.ts create mode 100644 server/src/lib/configuration/schema/StorageConfiguration.ts create mode 100644 server/src/lib/configuration/schema/TotpConfiguration.ts create mode 100644 server/src/lib/configuration/schema/UserDatabaseConfiguration.ts rename server/{test/connectors/mongo/MongoClient.test.ts => src/lib/connectors/mongo/MongoClient.spec.ts} (89%) rename server/{test/mocks/connectors/mongo/MongoClientStub.ts => src/lib/connectors/mongo/MongoClientStub.spec.ts} (100%) rename server/{test/connectors/mongo/MongoConnector.test.ts => src/lib/connectors/mongo/MongoConnector.spec.ts} (87%) rename server/{test/connectors/mongo/MongoConnectorFactory.test.ts => src/lib/connectors/mongo/MongoConnectorFactory.spec.ts} (65%) rename server/{test/ldap/Authenticator.test.ts => src/lib/ldap/Authenticator.spec.ts} (92%) rename server/{test/mocks/ldap/AuthenticatorStub.ts => src/lib/ldap/AuthenticatorStub.spec.ts} (87%) rename server/{test/ldap/Client.test.ts => src/lib/ldap/Client.spec.ts} (86%) rename server/{test/mocks/ldap/ClientFactoryStub.ts => src/lib/ldap/ClientFactoryStub.spec.ts} (100%) rename server/{test/mocks/ldap/ClientStub.ts => src/lib/ldap/ClientStub.spec.ts} (94%) rename server/{test/ldap/EmailsRetriever.test.ts => src/lib/ldap/EmailsRetriever.spec.ts} (84%) rename server/{test/mocks/ldap/EmailsRetrieverStub.ts => src/lib/ldap/EmailsRetrieverStub.spec.ts} (73%) rename server/{test/ldap/InputsSanitizer.test.ts => src/lib/ldap/InputsSanitizer.spec.ts} (90%) rename server/{test/mocks/ldap/LdapClientFactoryStub.ts => src/lib/ldap/LdapClientFactoryStub.spec.ts} (67%) rename server/{test/mocks/ldap/LdapClientStub.ts => src/lib/ldap/LdapClientStub.spec.ts} (93%) rename server/{test/ldap/PasswordUpdater.test.ts => src/lib/ldap/PasswordUpdater.spec.ts} (84%) rename server/{test/mocks/ldap/PasswordUpdaterStub.ts => src/lib/ldap/PasswordUpdaterStub.spec.ts} (74%) rename server/{test/ldap/SanitizedClient.test.ts => src/lib/ldap/SanitizedClient.spec.ts} (93%) rename server/{test/mocks/RequestLoggerStub.ts => src/lib/logging/RequestLoggerStub.spec.ts} (88%) rename server/{test/notifiers/EMailNotifier.test.ts => src/lib/notifiers/EmailNotifier.spec.ts} (82%) rename server/src/lib/notifiers/{EMailNotifier.ts => EmailNotifier.ts} (80%) rename server/{test/notifiers/MailSenderBuilder.test.ts => src/lib/notifiers/MailSenderBuilder.spec.ts} (93%) rename server/{test/mocks/notifiers/MailSenderBuilderStub.ts => src/lib/notifiers/MailSenderBuilderStub.spec.ts} (91%) rename server/{test/mocks/notifiers/MailSenderStub.ts => src/lib/notifiers/MailSenderStub.spec.ts} (100%) rename server/{test/notifiers/NotifierFactory.test.ts => src/lib/notifiers/NotifierFactory.spec.ts} (71%) rename server/{test/mocks/NotifierStub.ts => src/lib/notifiers/NotifierStub.spec.ts} (85%) rename server/{test/regulation/Regulator.test.ts => src/lib/regulation/Regulator.spec.ts} (96%) create mode 100644 server/src/lib/regulation/RegulatorStub.spec.ts rename server/{test/routes/errors/401/get.test.ts => src/lib/routes/error/401/get.spec.ts} (87%) rename server/{test/routes/errors/403/get.test.ts => src/lib/routes/error/403/get.spec.ts} (87%) rename server/{test/routes/errors/404/get.test.ts => src/lib/routes/error/404/get.spec.ts} (79%) rename server/{test/routes/firstfactor/post.test.ts => src/lib/routes/firstfactor/post.spec.ts} (82%) rename server/{test/routes/password-reset/post.test.ts => src/lib/routes/password-reset/form/post.spec.ts} (83%) rename server/{test/routes/password-reset/identity/PasswordResetHandler.test.ts => src/lib/routes/password-reset/identity/PasswordResetHandler.spec.ts} (84%) rename server/{test/routes/secondfactor/get.test.ts => src/lib/routes/secondfactor/get.spec.ts} (83%) rename server/{test/routes/secondfactor/redirect.test.ts => src/lib/routes/secondfactor/redirect.spec.ts} (76%) rename server/{test/routes/secondfactor/totp/register/RegistrationHandler.test.ts => src/lib/routes/secondfactor/totp/identity/RegistrationHandler.spec.ts} (87%) rename server/{test/routes/secondfactor/totp/sign/post.test.ts => src/lib/routes/secondfactor/totp/sign/post.spec.ts} (75%) rename server/{test/routes/secondfactor/u2f/identity/RegistrationHandler.test.ts => src/lib/routes/secondfactor/u2f/identity/RegistrationHandler.spec.ts} (86%) rename server/{test/routes/secondfactor/u2f/register/post.test.ts => src/lib/routes/secondfactor/u2f/register/post.spec.ts} (88%) rename server/{test/routes/secondfactor/u2f/register_request/get.test.ts => src/lib/routes/secondfactor/u2f/register_request/get.spec.ts} (85%) rename server/{test/routes/secondfactor/u2f/sign/post.test.ts => src/lib/routes/secondfactor/u2f/sign/post.spec.ts} (86%) rename server/{test/routes/secondfactor/u2f/sign_request/get.test.ts => src/lib/routes/secondfactor/u2f/sign_request/get.spec.ts} (76%) rename server/{test/routes/verify/get.test.ts => src/lib/routes/verify/get.spec.ts} (95%) rename server/{test/mocks/storage/CollectionFactoryStub.ts => src/lib/storage/CollectionFactoryStub.spec.ts} (70%) rename server/{test/mocks/storage/CollectionStub.ts => src/lib/storage/CollectionStub.spec.ts} (94%) rename server/{test/storage/UserDataStore.test.ts => src/lib/storage/UserDataStore.spec.ts} (94%) rename server/{test/mocks/storage/UserDataStoreStub.ts => src/lib/storage/UserDataStoreStub.spec.ts} (85%) rename server/{test/storage/mongo/MongoCollection.test.ts => src/lib/storage/mongo/MongoCollection.spec.ts} (94%) rename server/{test/storage/mongo/MongoCollectionFactory.test.ts => src/lib/storage/mongo/MongoCollectionFactory.spec.ts} (66%) rename server/{test/storage/nedb/NedbCollection.test.ts => src/lib/storage/nedb/NedbCollection.spec.ts} (96%) rename server/{test/storage/nedb/NedbCollectionFactory.test.ts => src/lib/storage/nedb/NedbCollectionFactory.spec.ts} (69%) rename server/{test/mocks/express.ts => src/lib/stubs/express.spec.ts} (100%) rename server/{test/mocks/ldapjs.ts => src/lib/stubs/ldapjs.spec.ts} (100%) rename server/{test/mocks/speakeasy.ts => src/lib/stubs/speakeasy.spec.ts} (100%) rename server/{test/mocks/u2f.ts => src/lib/stubs/u2f.spec.ts} (100%) rename server/{test/utils/DomainExtractor.test.ts => src/lib/utils/DomainExtractor.spec.ts} (85%) rename server/{test/utils/HashGenerator.test.ts => src/lib/utils/HashGenerator.spec.ts} (86%) delete mode 100644 server/test/configuration/LdapConfigurationAdaptation.test.ts delete mode 100644 server/test/configuration/Validator.test.ts delete mode 100644 server/test/configuration/adapters/ACLAdapter.test.ts delete mode 100644 server/test/configuration/adapters/AuthenticationMethodsAdapter.test.ts delete mode 100644 server/test/mocks/AuthenticationRegulator.ts delete mode 100644 server/test/mocks/IdentityValidator.ts delete mode 100644 server/test/mocks/Notifier.ts delete mode 100644 server/test/mocks/RegulatorStub.ts delete mode 100644 server/test/mocks/TOTPValidator.ts diff --git a/.travis.yml b/.travis.yml index 27105ca44..077e57022 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,4 @@ -dist: trusty language: node_js -sudo: required node_js: - "8" services: diff --git a/Gruntfile.js b/Gruntfile.js index b25a01433..068897681 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -19,7 +19,7 @@ module.exports = function (grunt) { "generate-config-schema": { cmd: "./node_modules/.bin/typescript-json-schema", args: ["-o", schemaDir, "--strictNullChecks", - "--required", "server/tsconfig.json", "UserConfiguration"] + "--required", "server/tsconfig.json", "Configuration"] }, "compile-client": { cmd: "./node_modules/.bin/tsc", @@ -35,11 +35,11 @@ module.exports = function (grunt) { }, "test-server-unit": { cmd: "./node_modules/.bin/mocha", - args: ['--colors', '--compilers', 'ts:ts-node/register', '--recursive', 'server/test'] + args: ['--colors', '--require', 'ts-node/register', 'server/src/**/*.spec.ts'] }, "test-client-unit": { cmd: "./node_modules/.bin/mocha", - args: ['--colors', '--compilers', 'ts:ts-node/register', '--recursive', 'client/test'] + args: ['--colors', '--require', 'ts-node/register', 'client/test/**/*.test.ts'] }, "test-int": { cmd: "./scripts/run-cucumber.sh", diff --git a/config.minimal.yml b/config.minimal.yml new file mode 100644 index 000000000..0a910b1be --- /dev/null +++ b/config.minimal.yml @@ -0,0 +1,24 @@ +############################################################### +# Authelia minimal configuration # +############################################################### + +ldap: + url: ldap://openldap + base_dn: dc=example,dc=com + + additional_users_dn: ou=users + additional_groups_dn: ou=groups + + groups_filter: (&(member={dn})(objectclass=groupOfNames)) + + user: cn=admin,dc=example,dc=com + password: password + +session: + # The secret to encrypt the session cookies. + secret: unsecure_session_secret + + # The domain to protect. + # Note: the authenticator must also be in that domain. If empty, the cookie + # is restricted to the subdomain of the issuer. + domain: example.com diff --git a/config.template.yml b/config.template.yml index 5022d6e35..c127f1c2d 100644 --- a/config.template.yml +++ b/config.template.yml @@ -191,10 +191,11 @@ session: # time. regulation: # The number of failed login attempts before user is banned. - # Set it to 0 for disabling regulation. + # Set it to 0 to disable regulation. max_retries: 3 - # The length of time between login attempts before user is banned. + # The time range during which the user can attempt login before being banned. + # The user is banned if the authenticaction failed `max_retries` times in a `find_time` seconds window. find_time: 120 # The length of time before a banned user can login again. diff --git a/server/src/lib/AuthenticationSessionHandler.ts b/server/src/lib/AuthenticationSessionHandler.ts index 2349490b8..ae2ff7c53 100644 --- a/server/src/lib/AuthenticationSessionHandler.ts +++ b/server/src/lib/AuthenticationSessionHandler.ts @@ -29,7 +29,7 @@ export class AuthenticationSessionHandler { static get(req: express.Request, logger: IRequestLogger): AuthenticationSession { if (!req.session) { - const errorMsg = "Something is wrong with session cookies. Please check Redis is running and Authelia can contact it."; + const errorMsg = "Something is wrong with session cookies. Please check Redis is running and Authelia can connect to it."; logger.error(req, errorMsg); throw new Error(errorMsg); } diff --git a/server/test/IdentityCheckMiddleware.test.ts b/server/src/lib/IdentityCheckMiddleware.spec.ts similarity index 73% rename from server/test/IdentityCheckMiddleware.test.ts rename to server/src/lib/IdentityCheckMiddleware.spec.ts index f59832d67..5f2b23a4b 100644 --- a/server/test/IdentityCheckMiddleware.test.ts +++ b/server/src/lib/IdentityCheckMiddleware.spec.ts @@ -1,32 +1,32 @@ import sinon = require("sinon"); -import IdentityValidator = require("../src/lib/IdentityCheckMiddleware"); +import IdentityValidator = require("./IdentityCheckMiddleware"); import { AuthenticationSessionHandler } - from "../src/lib/AuthenticationSessionHandler"; -import { AuthenticationSession } from "../types/AuthenticationSession"; -import { UserDataStore } from "../src/lib/storage/UserDataStore"; -import exceptions = require("../src/lib/Exceptions"); -import { ServerVariables } from "../src/lib/ServerVariables"; + from "./AuthenticationSessionHandler"; +import { AuthenticationSession } from "../../types/AuthenticationSession"; +import { UserDataStore } from "./storage/UserDataStore"; +import exceptions = require("./Exceptions"); +import { ServerVariables } from "./ServerVariables"; import Assert = require("assert"); import express = require("express"); import BluebirdPromise = require("bluebird"); -import ExpressMock = require("./mocks/express"); -import NotifierMock = require("./mocks/Notifier"); -import IdentityValidatorMock = require("./mocks/IdentityValidator"); -import { RequestLoggerStub } from "./mocks/RequestLoggerStub"; +import ExpressMock = require("./stubs/express.spec"); +import NotifierMock = require("./notifiers/NotifierStub.spec"); +import { IdentityValidableStub } from "./IdentityValidableStub.spec"; +import { RequestLoggerStub } from "./logging/RequestLoggerStub.spec"; import { ServerVariablesMock, ServerVariablesMockBuilder } - from "./mocks/ServerVariablesMockBuilder"; + from "./ServerVariablesMockBuilder.spec"; import { PRE_VALIDATION_TEMPLATE } - from "../src/lib/IdentityCheckPreValidationTemplate"; + from "./IdentityCheckPreValidationTemplate"; -describe("test identity check process", function () { +describe("IdentityCheckMiddleware", function () { let req: ExpressMock.RequestMock; let res: ExpressMock.ResponseMock; let app: express.Application; let app_get: sinon.SinonStub; let app_post: sinon.SinonStub; - let identityValidable: IdentityValidatorMock.IdentityValidableMock; + let identityValidable: IdentityValidableStub; let mocks: ServerVariablesMock; let vars: ServerVariables; @@ -38,8 +38,6 @@ describe("test identity check process", function () { req = ExpressMock.RequestMock(); res = ExpressMock.ResponseMock(); - identityValidable = IdentityValidatorMock.IdentityValidableMock(); - req.headers = {}; req.originalUrl = "/non-api/xxx"; req.session = {}; @@ -47,6 +45,8 @@ describe("test identity check process", function () { req.query = {}; req.app = {}; + identityValidable = new IdentityValidableStub(); + mocks.notifier.notifyStub.returns(BluebirdPromise.resolve()); mocks.userDataStore.produceIdentityValidationTokenStub .returns(BluebirdPromise.resolve()); @@ -66,7 +66,7 @@ describe("test identity check process", function () { describe("test start GET", function () { it("should redirect to error 401 if pre validation initialization \ throws a first factor error", function () { - identityValidable.preValidationInit.returns(BluebirdPromise.reject( + identityValidable.preValidationInitStub.returns(BluebirdPromise.reject( new exceptions.FirstFactorValidationError( "Error during prevalidation"))); const callback = IdentityValidator.get_start_validation( @@ -83,14 +83,14 @@ throws a first factor error", function () { it("should send 200 if email is missing in provided identity", function () { const identity = { userid: "abc" }; - identityValidable.preValidationInit + identityValidable.preValidationInitStub .returns(BluebirdPromise.resolve(identity)); const callback = IdentityValidator .get_start_validation(identityValidable, "/endpoint", vars); return callback(req as any, res as any, undefined) .then(function () { - Assert(identityValidable.preValidationResponse.called); + Assert(identityValidable.preValidationResponseStub.called); }); }); @@ -100,14 +100,14 @@ throws a first factor error", function () { const endpoint = "/protected"; const identity = { email: "abc@example.com" }; - identityValidable.preValidationInit + identityValidable.preValidationInitStub .returns(BluebirdPromise.resolve(identity)); const callback = IdentityValidator .get_start_validation(identityValidable, "/endpoint", vars); return callback(req as any, res as any, undefined) .then(function () { - Assert(identityValidable.preValidationResponse.called); + Assert(identityValidable.preValidationResponseStub.called); }); }); @@ -116,7 +116,7 @@ throws a first factor error", function () { const identity = { userid: "user", email: "abc@example.com" }; req.get = sinon.stub().withArgs("Host").returns("localhost"); - identityValidable.preValidationInit + identityValidable.preValidationInitStub .returns(BluebirdPromise.resolve(identity)); const callback = IdentityValidator .get_start_validation(identityValidable, "/finish_endpoint", vars); @@ -177,24 +177,5 @@ valid", function () { Assert(res.redirect.calledWith("/error/401")); }); }); - - it("should set the identity_check session object even if session does \ -not exist yet", function () { - req.query.identity_token = "token"; - - req.session = {}; - const authSession = - AuthenticationSessionHandler.get(req as any, vars.logger); - const callback = IdentityValidator - .get_finish_validation(identityValidable, vars); - - return callback(req as any, res as any, undefined) - .then(function () { - return BluebirdPromise.reject("Should fail"); - }) - .catch(function () { - Assert.equal(authSession.identity_check.userid, "user"); - }); - }); }); }); diff --git a/server/src/lib/IdentityCheckMiddleware.ts b/server/src/lib/IdentityCheckMiddleware.ts index 4a6486595..1163aea68 100644 --- a/server/src/lib/IdentityCheckMiddleware.ts +++ b/server/src/lib/IdentityCheckMiddleware.ts @@ -1,4 +1,3 @@ - import objectPath = require("object-path"); import randomstring = require("randomstring"); import BluebirdPromise = require("bluebird"); @@ -12,6 +11,7 @@ import ErrorReplies = require("./ErrorReplies"); import { AuthenticationSessionHandler } from "./AuthenticationSessionHandler"; import { AuthenticationSession } from "../../types/AuthenticationSession"; import { ServerVariables } from "./ServerVariables"; +import { IdentityValidable } from "./IdentityValidable"; import Identity = require("../../types/Identity"); import { IdentityValidationDocument } @@ -20,26 +20,9 @@ import { IdentityValidationDocument } const filePath = __dirname + "/../resources/email-template.ejs"; const email_template = fs.readFileSync(filePath, "utf8"); -// IdentityValidator allows user to go through a identity validation process -// in two steps: -// - Request an operation to be performed (password reset, registration). -// - Confirm operation with email. - -export interface IdentityValidable { - challenge(): string; - preValidationInit(req: Express.Request): BluebirdPromise; - postValidationInit(req: Express.Request): BluebirdPromise; - - // Serves a page after identity check request - preValidationResponse(req: Express.Request, res: Express.Response): void; - // Serves the page if identity validated - postValidationResponse(req: Express.Request, res: Express.Response): void; - mailSubject(): string; -} - function createAndSaveToken(userid: string, challenge: string, - userDataStore: IUserDataStore) - : BluebirdPromise { + userDataStore: IUserDataStore): BluebirdPromise { + const five_minutes = 4 * 60 * 1000; const token = randomstring.generate({ length: 64 }); const that = this; @@ -80,8 +63,10 @@ function checkIdentityToken(req: Express.Request, identityToken: string) export function get_finish_validation(handler: IdentityValidable, vars: ServerVariables) : Express.RequestHandler { + return function (req: Express.Request, res: Express.Response) : BluebirdPromise { + let authSession: AuthenticationSession; const identityToken = objectPath.get( req, "query.identity_token"); diff --git a/server/src/lib/IdentityValidable.ts b/server/src/lib/IdentityValidable.ts new file mode 100644 index 000000000..075580c9e --- /dev/null +++ b/server/src/lib/IdentityValidable.ts @@ -0,0 +1,19 @@ +import Bluebird = require("bluebird"); +import Identity = require("../../types/Identity"); + +// IdentityValidator allows user to go through a identity validation process +// in two steps: +// - Request an operation to be performed (password reset, registration). +// - Confirm operation with email. + +export interface IdentityValidable { + challenge(): string; + preValidationInit(req: Express.Request): Bluebird; + postValidationInit(req: Express.Request): Bluebird; + + // Serves a page after identity check request + preValidationResponse(req: Express.Request, res: Express.Response): void; + // Serves the page if identity validated + postValidationResponse(req: Express.Request, res: Express.Response): void; + mailSubject(): string; +} \ No newline at end of file diff --git a/server/src/lib/IdentityValidableStub.spec.ts b/server/src/lib/IdentityValidableStub.spec.ts new file mode 100644 index 000000000..f8722a63f --- /dev/null +++ b/server/src/lib/IdentityValidableStub.spec.ts @@ -0,0 +1,52 @@ + +import Sinon = require("sinon"); +import { IdentityValidable } from "./IdentityValidable"; +import express = require("express"); +import Bluebird = require("bluebird"); +import { Identity } from "../../types/Identity"; + + +export class IdentityValidableStub implements IdentityValidable { + challengeStub: Sinon.SinonStub; + preValidationInitStub: Sinon.SinonStub; + postValidationInitStub: Sinon.SinonStub; + preValidationResponseStub: Sinon.SinonStub; + postValidationResponseStub: Sinon.SinonStub; + mailSubjectStub: Sinon.SinonStub; + + constructor() { + this.challengeStub = Sinon.stub(); + + this.preValidationInitStub = Sinon.stub(); + this.postValidationResponseStub = Sinon.stub(); + + this.preValidationResponseStub = Sinon.stub(); + this.postValidationResponseStub = Sinon.stub(); + + this.mailSubjectStub = Sinon.stub(); + } + + challenge(): string { + return this.challengeStub(); + } + + preValidationInit(req: Express.Request): Bluebird { + return this.preValidationInitStub(req); + } + + postValidationInit(req: Express.Request): Bluebird { + return this.postValidationInitStub(req); + } + + preValidationResponse(req: Express.Request, res: Express.Response): void { + return this.preValidationResponseStub(req, res); + } + + postValidationResponse(req: Express.Request, res: Express.Response): void { + return this.postValidationResponseStub(req, res); + } + + mailSubject(): string { + return this.mailSubjectStub(); + } +} \ No newline at end of file diff --git a/server/test/ServerConfiguration.test.ts b/server/src/lib/Server.spec.ts similarity index 82% rename from server/test/ServerConfiguration.test.ts rename to server/src/lib/Server.spec.ts index bc6c1ba82..e3a00e1fe 100644 --- a/server/test/ServerConfiguration.test.ts +++ b/server/src/lib/Server.spec.ts @@ -7,13 +7,13 @@ import winston = require("winston"); import speakeasy = require("speakeasy"); import u2f = require("u2f"); import session = require("express-session"); -import { AppConfiguration, UserConfiguration } from "../src/lib/configuration/Configuration"; -import { GlobalDependencies } from "../types/Dependencies"; -import Server from "../src/lib/Server"; -import { LdapjsMock, LdapjsClientMock } from "./mocks/ldapjs"; +import { Configuration } from "./configuration/schema/Configuration"; +import { GlobalDependencies } from "../../types/Dependencies"; +import Server from "./Server"; +import { LdapjsMock, LdapjsClientMock } from "./stubs/ldapjs.spec"; -describe("test server configuration", function () { +describe("Server", function () { let deps: GlobalDependencies; let sessionMock: Sinon.SinonSpy; let ldapjsMock: LdapjsMock; @@ -36,7 +36,7 @@ describe("test server configuration", function () { it("should set cookie scope to domain set in the config", function () { - const config: UserConfiguration = { + const config: Configuration = { port: 8081, session: { domain: "example.com", diff --git a/server/src/lib/Server.ts b/server/src/lib/Server.ts index ad8ebd2be..c8e969e7a 100644 --- a/server/src/lib/Server.ts +++ b/server/src/lib/Server.ts @@ -2,7 +2,7 @@ import BluebirdPromise = require("bluebird"); import ObjectPath = require("object-path"); import { AccessController } from "./access_control/AccessController"; -import { AppConfiguration, UserConfiguration } from "./configuration/Configuration"; +import { Configuration } from "./configuration/schema/Configuration"; import { GlobalDependencies } from "../../types/Dependencies"; import { UserDataStore } from "./storage/UserDataStore"; import { ConfigurationParser } from "./configuration/ConfigurationParser"; @@ -31,33 +31,22 @@ export default class Server { this.requestLogger = new RequestLogger(deps.winston); } - private displayConfigurations(userConfiguration: UserConfiguration, - appConfiguration: AppConfiguration) { - const displayableUserConfiguration = clone(userConfiguration); - const displayableAppConfiguration = clone(appConfiguration); + private displayConfigurations(configuration: Configuration) { + const displayableConfiguration: Configuration = clone(configuration); const STARS = "*****"; - displayableUserConfiguration.ldap.password = STARS; - displayableUserConfiguration.session.secret = STARS; - if (displayableUserConfiguration.notifier && displayableUserConfiguration.notifier.email) - displayableUserConfiguration.notifier.email.password = STARS; - if (displayableUserConfiguration.notifier && displayableUserConfiguration.notifier.smtp) - displayableUserConfiguration.notifier.smtp.password = STARS; - - displayableAppConfiguration.ldap.password = STARS; - displayableAppConfiguration.session.secret = STARS; - if (displayableAppConfiguration.notifier && displayableAppConfiguration.notifier.email) - displayableAppConfiguration.notifier.email.password = STARS; - if (displayableAppConfiguration.notifier && displayableAppConfiguration.notifier.smtp) - displayableAppConfiguration.notifier.smtp.password = STARS; + displayableConfiguration.ldap.password = STARS; + displayableConfiguration.session.secret = STARS; + if (displayableConfiguration.notifier && displayableConfiguration.notifier.email) + displayableConfiguration.notifier.email.password = STARS; + if (displayableConfiguration.notifier && displayableConfiguration.notifier.smtp) + displayableConfiguration.notifier.smtp.password = STARS; this.globalLogger.debug("User configuration is %s", - JSON.stringify(displayableUserConfiguration, undefined, 2)); - this.globalLogger.debug("Adapted configuration is %s", - JSON.stringify(displayableAppConfiguration, undefined, 2)); + JSON.stringify(displayableConfiguration, undefined, 2)); } - private setup(config: AppConfiguration, app: Express.Application, deps: GlobalDependencies): BluebirdPromise { + private setup(config: Configuration, app: Express.Application, deps: GlobalDependencies): BluebirdPromise { const that = this; return ServerVariablesInitializer.initialize(config, this.requestLogger, deps) .then(function (vars: ServerVariables) { @@ -76,16 +65,16 @@ export default class Server { }); } - start(userConfiguration: UserConfiguration, deps: GlobalDependencies) + start(configuration: Configuration, deps: GlobalDependencies) : BluebirdPromise { const that = this; const app = Express(); - const appConfiguration = ConfigurationParser.parse(userConfiguration); + const appConfiguration = ConfigurationParser.parse(configuration); // by default the level of logs is info - deps.winston.level = userConfiguration.logs_level; - this.displayConfigurations(userConfiguration, appConfiguration); + deps.winston.level = configuration.logs_level; + this.displayConfigurations(configuration); return this.setup(appConfiguration, app, deps) .then(function () { diff --git a/server/src/lib/ServerVariables.ts b/server/src/lib/ServerVariables.ts index a7b1e2e5e..cdd5285e2 100644 --- a/server/src/lib/ServerVariables.ts +++ b/server/src/lib/ServerVariables.ts @@ -7,7 +7,7 @@ import { IU2fHandler } from "./authentication/u2f/IU2fHandler"; import { IUserDataStore } from "./storage/IUserDataStore"; import { INotifier } from "./notifiers/INotifier"; import { IRegulator } from "./regulation/IRegulator"; -import { AppConfiguration } from "./configuration/Configuration"; +import { Configuration } from "./configuration/schema/Configuration"; import { IAccessController } from "./access_control/IAccessController"; export interface ServerVariables { @@ -20,6 +20,6 @@ export interface ServerVariables { userDataStore: IUserDataStore; notifier: INotifier; regulator: IRegulator; - config: AppConfiguration; + config: Configuration; accessController: IAccessController; } \ No newline at end of file diff --git a/server/src/lib/ServerVariablesInitializer.ts b/server/src/lib/ServerVariablesInitializer.ts index 9eed50f12..2a9f40977 100644 --- a/server/src/lib/ServerVariablesInitializer.ts +++ b/server/src/lib/ServerVariablesInitializer.ts @@ -26,7 +26,7 @@ import { UserDataStore } from "./storage/UserDataStore"; import { INotifier } from "./notifiers/INotifier"; import { Regulator } from "./regulation/Regulator"; import { IRegulator } from "./regulation/IRegulator"; -import Configuration = require("./configuration/Configuration"); +import Configuration = require("./configuration/schema/Configuration"); import { AccessController } from "./access_control/AccessController"; import { IAccessController } from "./access_control/IAccessController"; import { CollectionFactoryFactory } from "./storage/CollectionFactoryFactory"; @@ -40,7 +40,7 @@ import { ServerVariables } from "./ServerVariables"; import { MethodCalculator } from "./authentication/MethodCalculator"; class UserDataStoreFactory { - static create(config: Configuration.AppConfiguration): BluebirdPromise { + static create(config: Configuration.Configuration): BluebirdPromise { if (config.storage.local) { const nedbOptions: Nedb.DataStoreOptions = { filename: config.storage.local.path, @@ -64,7 +64,7 @@ class UserDataStoreFactory { } export class ServerVariablesInitializer { - static initialize(config: Configuration.AppConfiguration, requestLogger: IRequestLogger, + static initialize(config: Configuration.Configuration, requestLogger: IRequestLogger, deps: GlobalDependencies): BluebirdPromise { const mailSenderBuilder = new MailSenderBuilder(Nodemailer); const notifier = NotifierFactory.build(config.notifier, mailSenderBuilder); diff --git a/server/test/mocks/ServerVariablesMockBuilder.ts b/server/src/lib/ServerVariablesMockBuilder.spec.ts similarity index 70% rename from server/test/mocks/ServerVariablesMockBuilder.ts rename to server/src/lib/ServerVariablesMockBuilder.spec.ts index 7a4ef5ca9..a26218e1a 100644 --- a/server/test/mocks/ServerVariablesMockBuilder.ts +++ b/server/src/lib/ServerVariablesMockBuilder.spec.ts @@ -1,20 +1,20 @@ -import { ServerVariables } from "../../src/lib/ServerVariables"; +import { ServerVariables } from "./ServerVariables"; -import { AppConfiguration } from "../../src/lib/configuration/Configuration"; -import { AuthenticatorStub } from "./ldap/AuthenticatorStub"; -import { EmailsRetrieverStub } from "./ldap/EmailsRetrieverStub"; -import { PasswordUpdaterStub } from "./ldap/PasswordUpdaterStub"; -import { AccessControllerStub } from "./AccessControllerStub"; -import { RequestLoggerStub } from "./RequestLoggerStub"; -import { NotifierStub } from "./NotifierStub"; -import { RegulatorStub } from "./RegulatorStub"; -import { TotpHandlerStub } from "./TotpHandlerStub"; -import { UserDataStoreStub } from "./storage/UserDataStoreStub"; -import { U2fHandlerStub } from "./U2fHandlerStub"; +import { Configuration } from "./configuration/schema/Configuration"; +import { AuthenticatorStub } from "./ldap/AuthenticatorStub.spec"; +import { EmailsRetrieverStub } from "./ldap/EmailsRetrieverStub.spec"; +import { PasswordUpdaterStub } from "./ldap/PasswordUpdaterStub.spec"; +import { AccessControllerStub } from "./access_control/AccessControllerStub.spec"; +import { RequestLoggerStub } from "./logging/RequestLoggerStub.spec"; +import { NotifierStub } from "./notifiers/NotifierStub.spec"; +import { RegulatorStub } from "./regulation/RegulatorStub.spec"; +import { TotpHandlerStub } from "./authentication/totp/TotpHandlerStub.spec"; +import { UserDataStoreStub } from "./storage/UserDataStoreStub.spec"; +import { U2fHandlerStub } from "./authentication/u2f/U2fHandlerStub.spec"; export interface ServerVariablesMock { accessController: AccessControllerStub; - config: AppConfiguration; + config: Configuration; ldapAuthenticator: AuthenticatorStub; ldapEmailsRetriever: EmailsRetrieverStub; ldapPasswordUpdater: PasswordUpdaterStub; @@ -40,11 +40,12 @@ export class ServerVariablesMockBuilder { }, ldap: { url: "ldap://ldap", + base_dn: "dc=example,dc=com", user: "user", password: "password", mail_attribute: "mail", - users_dn: "ou=users,dc=example,dc=com", - groups_dn: "ou=groups,dc=example,dc=com", + additional_users_dn: "ou=users", + additional_groups_dn: "ou=groups", users_filter: "cn={0}", groups_filter: "member={dn}", group_name_attribute: "cn" diff --git a/server/test/access_control/AccessController.test.ts b/server/src/lib/access_control/AccessController.spec.ts similarity index 98% rename from server/test/access_control/AccessController.test.ts rename to server/src/lib/access_control/AccessController.spec.ts index 322c3540a..057e23d8e 100644 --- a/server/test/access_control/AccessController.test.ts +++ b/server/src/lib/access_control/AccessController.spec.ts @@ -1,10 +1,10 @@ import Assert = require("assert"); import winston = require("winston"); -import { AccessController } from "../../src/lib/access_control/AccessController"; -import { ACLConfiguration, ACLRule } from "../../src/lib/configuration/Configuration"; +import { AccessController } from "./AccessController"; +import { ACLConfiguration, ACLRule } from "../configuration/schema/AclConfiguration"; -describe("test access control manager", function () { +describe("access_control/AccessController", function () { let accessController: AccessController; let configuration: ACLConfiguration; diff --git a/server/src/lib/access_control/AccessController.ts b/server/src/lib/access_control/AccessController.ts index a7a572080..dd7328fdd 100644 --- a/server/src/lib/access_control/AccessController.ts +++ b/server/src/lib/access_control/AccessController.ts @@ -1,5 +1,5 @@ -import { ACLConfiguration, ACLPolicy, ACLRule } from "../configuration/Configuration"; +import { ACLConfiguration, ACLPolicy, ACLRule } from "../configuration/schema/AclConfiguration"; import { IAccessController } from "./IAccessController"; import { Winston } from "../../../types/Dependencies"; import { MultipleDomainMatcher } from "./MultipleDomainMatcher"; diff --git a/server/test/mocks/AccessControllerStub.ts b/server/src/lib/access_control/AccessControllerStub.spec.ts similarity index 81% rename from server/test/mocks/AccessControllerStub.ts rename to server/src/lib/access_control/AccessControllerStub.spec.ts index e295cdab9..607454690 100644 --- a/server/test/mocks/AccessControllerStub.ts +++ b/server/src/lib/access_control/AccessControllerStub.spec.ts @@ -1,6 +1,5 @@ - import Sinon = require("sinon"); -import { IAccessController } from "../../src/lib/access_control/IAccessController"; +import { IAccessController } from "./IAccessController"; export class AccessControllerStub implements IAccessController { isAccessAllowedMock: Sinon.SinonStub; diff --git a/server/test/authentication/MethodCalculator.test.ts b/server/src/lib/authentication/MethodCalculator.spec.ts similarity index 93% rename from server/test/authentication/MethodCalculator.test.ts rename to server/src/lib/authentication/MethodCalculator.spec.ts index 45b3ee2f8..6c6c916a0 100644 --- a/server/test/authentication/MethodCalculator.test.ts +++ b/server/src/lib/authentication/MethodCalculator.spec.ts @@ -1,10 +1,9 @@ -import { MethodCalculator } - from "../../src/lib/authentication/MethodCalculator"; +import { MethodCalculator } from "./MethodCalculator"; import { AuthenticationMethodsConfiguration } - from "../../src/lib/configuration/Configuration"; + from "../configuration/schema/AuthenticationMethodsConfiguration"; import Assert = require("assert"); -describe("test MethodCalculator", function () { +describe("authentication/MethodCalculator", function () { describe("test compute method", function () { it("should return default method when sub domain not overriden", function () { diff --git a/server/src/lib/authentication/MethodCalculator.ts b/server/src/lib/authentication/MethodCalculator.ts index d18a83f38..961a8402d 100644 --- a/server/src/lib/authentication/MethodCalculator.ts +++ b/server/src/lib/authentication/MethodCalculator.ts @@ -1,7 +1,7 @@ import { AuthenticationMethod, AuthenticationMethodsConfiguration -} from "../configuration/Configuration"; +} from "../configuration/schema/AuthenticationMethodsConfiguration"; function computeIsSingleFactorOnlyMode( configuration: AuthenticationMethodsConfiguration): boolean { diff --git a/server/test/authentication/totp/Validator.test.ts b/server/src/lib/authentication/totp/TotpHandler.spec.ts similarity index 88% rename from server/test/authentication/totp/Validator.test.ts rename to server/src/lib/authentication/totp/TotpHandler.spec.ts index 3d0518440..67cffa638 100644 --- a/server/test/authentication/totp/Validator.test.ts +++ b/server/src/lib/authentication/totp/TotpHandler.spec.ts @@ -1,10 +1,10 @@ -import { TotpHandler } from "../../../src/lib/authentication/totp/TotpHandler"; +import { TotpHandler } from "./TotpHandler"; import Sinon = require("sinon"); import Speakeasy = require("speakeasy"); import Assert = require("assert"); -describe("test TOTP validation", function() { +describe("authentication/totp/TotpHandler", function() { let totpValidator: TotpHandler; let validateStub: Sinon.SinonStub; diff --git a/server/test/mocks/TotpHandlerStub.ts b/server/src/lib/authentication/totp/TotpHandlerStub.spec.ts similarity index 79% rename from server/test/mocks/TotpHandlerStub.ts rename to server/src/lib/authentication/totp/TotpHandlerStub.spec.ts index 8b261effe..ea93330d9 100644 --- a/server/test/mocks/TotpHandlerStub.ts +++ b/server/src/lib/authentication/totp/TotpHandlerStub.spec.ts @@ -1,7 +1,7 @@ import Sinon = require("sinon"); import BluebirdPromise = require("bluebird"); -import { ITotpHandler } from "../../src/lib/authentication/totp/ITotpHandler"; -import { TOTPSecret } from "../../types/TOTPSecret"; +import { ITotpHandler } from "./ITotpHandler"; +import { TOTPSecret } from "../../../../types/TOTPSecret"; export class TotpHandlerStub implements ITotpHandler { generateStub: Sinon.SinonStub; diff --git a/server/test/mocks/U2fHandlerStub.ts b/server/src/lib/authentication/u2f/U2fHandlerStub.spec.ts similarity index 92% rename from server/test/mocks/U2fHandlerStub.ts rename to server/src/lib/authentication/u2f/U2fHandlerStub.spec.ts index 95256641f..135d7eb06 100644 --- a/server/test/mocks/U2fHandlerStub.ts +++ b/server/src/lib/authentication/u2f/U2fHandlerStub.spec.ts @@ -1,7 +1,7 @@ import Sinon = require("sinon"); import BluebirdPromise = require("bluebird"); import U2f = require("u2f"); -import { IU2fHandler } from "../../src/lib/authentication/u2f/IU2fHandler"; +import { IU2fHandler } from "./IU2fHandler"; export class U2fHandlerStub implements IU2fHandler { diff --git a/server/src/lib/configuration/Configuration.d.ts b/server/src/lib/configuration/Configuration.d.ts deleted file mode 100644 index 20555b993..000000000 --- a/server/src/lib/configuration/Configuration.d.ts +++ /dev/null @@ -1,155 +0,0 @@ -export interface UserLdapConfiguration { - url: string; - base_dn: string; - - additional_users_dn?: string; - users_filter?: string; - - additional_groups_dn?: string; - groups_filter?: string; - - group_name_attribute?: string; - mail_attribute?: string; - - user: string; // admin username - password: string; // admin password -} - -export interface LdapConfiguration { - url: string; - - users_dn: string; - users_filter: string; - - groups_dn: string; - groups_filter: string; - - group_name_attribute: string; - mail_attribute: string; - - user: string; // admin username - password: string; // admin password -} - -type UserName = string; -type GroupName = string; -type DomainPattern = string; - -export type ACLPolicy = 'deny' | 'allow'; - -export type ACLRule = { - domain: string; - policy: ACLPolicy; - resources?: string[]; -} - -export type ACLDefaultRules = ACLRule[]; -export type ACLGroupsRules = { [group: string]: ACLRule[]; }; -export type ACLUsersRules = { [user: string]: ACLRule[]; }; - -export interface ACLConfiguration { - default_policy?: ACLPolicy; - any?: ACLDefaultRules; - groups?: ACLGroupsRules; - users?: ACLUsersRules; -} - -export interface SessionRedisOptions { - host: string; - port: number; -} - -interface SessionCookieConfiguration { - secret: string; - expiration?: number; - inactivity?: number; - domain: string; - redis?: SessionRedisOptions; -} - -export interface EmailNotifierConfiguration { - username: string; - password: string; - sender: string; - service: string; -} - -export interface SmtpNotifierConfiguration { - username?: string; - password?: string; - host: string; - port: number; - secure: boolean; - sender: string; -} - -export interface FileSystemNotifierConfiguration { - filename: string; -} - -export interface NotifierConfiguration { - email?: EmailNotifierConfiguration; - smtp?: SmtpNotifierConfiguration; - filesystem?: FileSystemNotifierConfiguration; -} - -export interface MongoStorageConfiguration { - url: string; - database: string; -} - -export interface LocalStorageConfiguration { - path?: string; - in_memory?: boolean; -} - -export interface StorageConfiguration { - local?: LocalStorageConfiguration; - mongo?: MongoStorageConfiguration; -} - -export interface RegulationConfiguration { - max_retries: number; - find_time: number; - ban_time: number; -} - -declare type AuthenticationMethod = 'two_factor' | 'single_factor'; -declare type AuthenticationMethodPerSubdomain = { [subdomain: string]: AuthenticationMethod } - -export interface AuthenticationMethodsConfiguration { - default_method: AuthenticationMethod; - per_subdomain_methods?: AuthenticationMethodPerSubdomain; -} - -export interface TOTPConfiguration { - issuer: string; -} - -export interface UserConfiguration { - port?: number; - logs_level?: string; - ldap: UserLdapConfiguration; - session: SessionCookieConfiguration; - storage: StorageConfiguration; - notifier: NotifierConfiguration; - authentication_methods?: AuthenticationMethodsConfiguration; - access_control?: ACLConfiguration; - regulation: RegulationConfiguration; - default_redirection_url?: string; - totp?: TOTPConfiguration; -} - -export interface AppConfiguration { - port: number; - logs_level: string; - ldap: LdapConfiguration; - session: SessionCookieConfiguration; - storage: StorageConfiguration; - notifier: NotifierConfiguration; - authentication_methods: AuthenticationMethodsConfiguration; - access_control?: ACLConfiguration; - regulation: RegulationConfiguration; - default_redirection_url?: string; - totp: TOTPConfiguration; -} diff --git a/server/test/configuration/ConfigurationParser.test.ts b/server/src/lib/configuration/ConfigurationParser.spec.ts similarity index 92% rename from server/test/configuration/ConfigurationParser.test.ts rename to server/src/lib/configuration/ConfigurationParser.spec.ts index 107a94ebe..bb304386d 100644 --- a/server/test/configuration/ConfigurationParser.test.ts +++ b/server/src/lib/configuration/ConfigurationParser.spec.ts @@ -1,13 +1,11 @@ import * as Assert from "assert"; -import { - UserConfiguration, - LdapConfiguration, ACLConfiguration -} from "../../src/lib/configuration/Configuration"; -import { ConfigurationParser } from "../../src/lib/configuration/ConfigurationParser"; +import { Configuration } from "./schema/Configuration"; +import { ACLConfiguration } from "./schema/AclConfiguration"; +import { ConfigurationParser } from "./ConfigurationParser"; -describe("test config parser", function () { - function buildYamlConfig(): UserConfiguration { - const yaml_config: UserConfiguration = { +describe("configuration/ConfigurationParser", function () { + function buildYamlConfig(): Configuration { + const yaml_config: Configuration = { port: 8080, ldap: { url: "http://ldap", @@ -160,11 +158,11 @@ describe("test config parser", function () { userConfig.access_control = {} as any; const config = ConfigurationParser.parse(userConfig); Assert.deepEqual(config.access_control, { - default_policy: "deny", + default_policy: "allow", any: [], users: {}, groups: {} - } as ACLConfiguration); + }); }); }); diff --git a/server/src/lib/configuration/ConfigurationParser.ts b/server/src/lib/configuration/ConfigurationParser.ts index 858936311..a67632c3b 100644 --- a/server/src/lib/configuration/ConfigurationParser.ts +++ b/server/src/lib/configuration/ConfigurationParser.ts @@ -1,109 +1,39 @@ import * as ObjectPath from "object-path"; -import { - AppConfiguration, UserConfiguration, NotifierConfiguration, - ACLConfiguration, LdapConfiguration, SessionRedisOptions, - MongoStorageConfiguration, LocalStorageConfiguration, - UserLdapConfiguration -} from "./Configuration"; +import { Configuration, complete } from "./schema/Configuration"; +import Ajv = require("ajv"); +import Path = require("path"); import Util = require("util"); -import { ACLAdapter } from "./adapters/ACLAdapter"; -import { TOTPAdapter } from "./adapters/TOTPAdapter"; -import { AuthenticationMethodsAdapter } from "./adapters/AuthenticationMethodsAdapter"; -import { Validator } from "./Validator"; - -const LDAP_URL_ENV_VARIABLE = "LDAP_URL"; - -function get_optional(config: object, path: string, default_value: T): T { - let entry = default_value; - if (ObjectPath.has(config, path)) { - entry = ObjectPath.get(config, path); - } - return entry; -} - -function ensure_key_existence(config: object, path: string): void { - if (!ObjectPath.has(config, path)) { - throw new Error(`Configuration error: key '${path}' is missing in configuration file`); - } -} - -function adaptLdapConfiguration(userConfig: UserLdapConfiguration): LdapConfiguration { - const DEFAULT_USERS_FILTER = "cn={0}"; - const DEFAULT_GROUPS_FILTER = "member={dn}"; - const DEFAULT_GROUP_NAME_ATTRIBUTE = "cn"; - const DEFAULT_MAIL_ATTRIBUTE = "mail"; - - let usersDN = userConfig.base_dn; - if (userConfig.additional_users_dn) - usersDN = userConfig.additional_users_dn + "," + usersDN; - - let groupsDN = userConfig.base_dn; - if (userConfig.additional_groups_dn) - groupsDN = userConfig.additional_groups_dn + "," + groupsDN; - - return { - url: userConfig.url, - users_dn: usersDN, - users_filter: userConfig.users_filter || DEFAULT_USERS_FILTER, - groups_dn: groupsDN, - groups_filter: userConfig.groups_filter || DEFAULT_GROUPS_FILTER, - group_name_attribute: userConfig.group_name_attribute || DEFAULT_GROUP_NAME_ATTRIBUTE, - mail_attribute: userConfig.mail_attribute || DEFAULT_MAIL_ATTRIBUTE, - password: userConfig.password, - user: userConfig.user - }; -} - -function adaptFromUserConfiguration(userConfiguration: UserConfiguration) - : AppConfiguration { - if (!Validator.isValid(userConfiguration)) - throw new Error("Configuration is malformed. Please double check your configuration file."); - - const port = userConfiguration.port || 8080; - const ldapConfiguration = adaptLdapConfiguration(userConfiguration.ldap); - const authenticationMethods = AuthenticationMethodsAdapter - .adapt(userConfiguration.authentication_methods); - const totpConfiguration = TOTPAdapter.adapt(userConfiguration.totp); - - return { - port: port, - ldap: ldapConfiguration, - session: { - domain: ObjectPath.get(userConfiguration, "session.domain"), - secret: ObjectPath.get(userConfiguration, "session.secret"), - expiration: get_optional(userConfiguration, "session.expiration", 3600000), // in ms - inactivity: get_optional(userConfiguration, "session.inactivity", undefined), - redis: ObjectPath.get(userConfiguration, "session.redis") - }, - storage: { - local: get_optional(userConfiguration, "storage.local", undefined), - mongo: get_optional(userConfiguration, "storage.mongo", undefined) - }, - logs_level: get_optional(userConfiguration, "logs_level", "info"), - notifier: ObjectPath.get(userConfiguration, "notifier"), - access_control: ACLAdapter.adapt(userConfiguration.access_control), - regulation: userConfiguration.regulation, - authentication_methods: authenticationMethods, - default_redirection_url: userConfiguration.default_redirection_url, - totp: totpConfiguration - }; -} export class ConfigurationParser { - static parse(userConfiguration: UserConfiguration): AppConfiguration { - const errors = Validator.isValid(userConfiguration); - if (errors.length > 0) { - errors.forEach((e: string) => { console.log(e); }); + private static parseTypes(configuration: Configuration): string[] { + const schema = require(Path.resolve(__dirname, "./Configuration.schema.json")); + const ajv = new Ajv({ + allErrors: true, + missingRefs: "fail" + }); + ajv.addMetaSchema(require("ajv/lib/refs/json-schema-draft-06.json")); + const valid = ajv.validate(schema, configuration); + if (!valid) + return ajv.errors.map( + (e: Ajv.ErrorObject) => { return ajv.errorsText([e]); }); + return []; + } + + static parse(configuration: Configuration): Configuration { + const validationErrors = this.parseTypes(configuration); + if (validationErrors.length > 0) { + validationErrors.forEach((e: string) => { console.log(e); }); throw new Error("Malformed configuration. Please double-check your configuration file."); } - const appConfiguration = adaptFromUserConfiguration(userConfiguration); - const ldapUrl = process.env[LDAP_URL_ENV_VARIABLE]; - if (ldapUrl) - appConfiguration.ldap.url = ldapUrl; + const [newConfiguration, completionErrors] = complete(configuration); - return appConfiguration; + if (completionErrors.length > 0) { + completionErrors.forEach((e: string) => { console.log(e); }); + throw new Error("Malformed configuration. Please double-check your configuration file."); + } + return newConfiguration; } } diff --git a/server/test/SessionConfigurationBuilder.test.ts b/server/src/lib/configuration/SessionConfigurationBuilder.spec.ts similarity index 87% rename from server/test/SessionConfigurationBuilder.test.ts rename to server/src/lib/configuration/SessionConfigurationBuilder.spec.ts index 6fc1359ac..0d5cc11fe 100644 --- a/server/test/SessionConfigurationBuilder.test.ts +++ b/server/src/lib/configuration/SessionConfigurationBuilder.spec.ts @@ -1,15 +1,15 @@ -import { SessionConfigurationBuilder } from "../src/lib/configuration/SessionConfigurationBuilder"; -import { AppConfiguration } from "../src/lib/configuration/Configuration"; -import { GlobalDependencies } from "../types/Dependencies"; +import { SessionConfigurationBuilder } from "./SessionConfigurationBuilder"; +import { Configuration } from "./schema/Configuration"; +import { GlobalDependencies } from "../../../types/Dependencies"; import ExpressSession = require("express-session"); import ConnectRedis = require("connect-redis"); import Sinon = require("sinon"); import Assert = require("assert"); -describe("test session configuration builder", function () { +describe("configuration/SessionConfigurationBuilder", function () { it("should return session options without redis options", function () { - const configuration: AppConfiguration = { + const configuration: Configuration = { access_control: { default_policy: "deny", any: [], @@ -22,9 +22,10 @@ describe("test session configuration builder", function () { ldap: { url: "ldap://ldap", user: "user", + base_dn: "dc=example,dc=com", password: "password", - groups_dn: "ou=groups,dc=example,dc=com", - users_dn: "ou=users,dc=example,dc=com", + additional_groups_dn: "ou=groups", + additional_users_dn: "ou=users", group_name_attribute: "", groups_filter: "", mail_attribute: "", @@ -87,7 +88,7 @@ describe("test session configuration builder", function () { }); it("should return session options with redis options", function () { - const configuration: AppConfiguration = { + const configuration: Configuration = { access_control: { default_policy: "deny", any: [], @@ -101,8 +102,9 @@ describe("test session configuration builder", function () { url: "ldap://ldap", user: "user", password: "password", - groups_dn: "ou=groups,dc=example,dc=com", - users_dn: "ou=users,dc=example,dc=com", + base_dn: "dc=example,dc=com", + additional_groups_dn: "ou=groups", + additional_users_dn: "ou=users", group_name_attribute: "", groups_filter: "", mail_attribute: "", diff --git a/server/src/lib/configuration/SessionConfigurationBuilder.ts b/server/src/lib/configuration/SessionConfigurationBuilder.ts index fa5e4443c..427cec728 100644 --- a/server/src/lib/configuration/SessionConfigurationBuilder.ts +++ b/server/src/lib/configuration/SessionConfigurationBuilder.ts @@ -1,11 +1,11 @@ import ExpressSession = require("express-session"); -import { AppConfiguration } from "./Configuration"; +import { Configuration } from "./schema/Configuration"; import { GlobalDependencies } from "../../../types/Dependencies"; export class SessionConfigurationBuilder { - static build(configuration: AppConfiguration, deps: GlobalDependencies): ExpressSession.SessionOptions { + static build(configuration: Configuration, deps: GlobalDependencies): ExpressSession.SessionOptions { const sessionOptions: ExpressSession.SessionOptions = { secret: configuration.session.secret, resave: false, diff --git a/server/src/lib/configuration/Validator.ts b/server/src/lib/configuration/Validator.ts deleted file mode 100644 index 307ed2bb2..000000000 --- a/server/src/lib/configuration/Validator.ts +++ /dev/null @@ -1,94 +0,0 @@ -import Ajv = require("ajv"); -import Path = require("path"); -import Util = require("util"); -import { - UserConfiguration, StorageConfiguration, - NotifierConfiguration, AuthenticationMethodsConfiguration -} from "./Configuration"; -import { MethodCalculator } from "../authentication/MethodCalculator"; - -function validateSchema(configuration: UserConfiguration): string[] { - const schema = require(Path.resolve(__dirname, "./Configuration.schema.json")); - const ajv = new Ajv({ - allErrors: true, - missingRefs: "fail" - }); - ajv.addMetaSchema(require("ajv/lib/refs/json-schema-draft-06.json")); - const valid = ajv.validate(schema, configuration); - if (!valid) - return ajv.errors.map( - (e: Ajv.ErrorObject) => { return ajv.errorsText([e]); }); - return []; -} - -function diff(a: string[], b: string[]) { - return a.filter(function(i) {return b.indexOf(i) < 0; }); -} - -function validateUnknownKeys(path: string, obj: any, knownKeys: string[]) { - const keysSet = Object.keys(obj); - - const unknownKeysSet = diff(keysSet, knownKeys); - if (unknownKeysSet.length > 0) { - const unknownKeys = Array.from(unknownKeysSet); - return unknownKeys.map((k: string) => { return Util.format("data.%s has unknown key '%s'", path, k); }); - } - return []; -} - -function validateStorage(storage: any): string[] { - const ERROR = "Storage must be either 'local' or 'mongo'"; - - if (!storage) - return []; - - const errors = validateUnknownKeys("storage", storage, ["local", "mongo"]); - if (errors.length > 0) - return errors; - - if (storage.local && storage.mongo) - return [ERROR]; - - if (!storage.local && !storage.mongo) - return [ERROR]; - - return []; -} - -function validateNotifier(notifier: NotifierConfiguration, - authenticationMethods: AuthenticationMethodsConfiguration): string[] { - const ERROR = "Notifier must be either 'filesystem', 'email' or 'smtp'"; - - if (!notifier) - return []; - - if (!MethodCalculator.isSingleFactorOnlyMode(authenticationMethods)) { - if (Object.keys(notifier).length != 1) - return ["A notifier needs to be declared when server is used with two-factor"]; - - if (notifier && notifier.filesystem && notifier.email && notifier.smtp) - return [ERROR]; - - if (notifier && !notifier.filesystem && !notifier.email && !notifier.smtp) - return [ERROR]; - } - - const errors = validateUnknownKeys("notifier", notifier, ["filesystem", "email", "smtp"]); - if (errors.length > 0) - return errors; - - return []; -} - -export class Validator { - static isValid(configuration: any): string[] { - const schemaErrors = validateSchema(configuration); - const storageErrors = validateStorage(configuration.storage); - const notifierErrors = validateNotifier(configuration.notifier, - configuration.authentication_methods); - - return schemaErrors - .concat(storageErrors) - .concat(notifierErrors); - } -} \ No newline at end of file diff --git a/server/src/lib/configuration/adapters/ACLAdapter.ts b/server/src/lib/configuration/adapters/ACLAdapter.ts deleted file mode 100644 index d9fca60b8..000000000 --- a/server/src/lib/configuration/adapters/ACLAdapter.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { ACLConfiguration } from "../Configuration"; -import { ObjectCloner } from "../../utils/ObjectCloner"; - -const DEFAULT_POLICY = "deny"; - -function adaptDefaultPolicy(configuration: ACLConfiguration) { - if (!configuration.default_policy) - configuration.default_policy = DEFAULT_POLICY; - if (configuration.default_policy != "deny" && configuration.default_policy != "allow") - configuration.default_policy = DEFAULT_POLICY; -} - -function adaptAny(configuration: ACLConfiguration) { - if (!configuration.any || !(configuration.any.constructor === Array)) - configuration.any = []; -} - -function adaptGroups(configuration: ACLConfiguration) { - if (!configuration.groups || !(configuration.groups.constructor === Object)) - configuration.groups = {}; -} - -function adaptUsers(configuration: ACLConfiguration) { - if (!configuration.users || !(configuration.users.constructor === Object)) - configuration.users = {}; -} - -export class ACLAdapter { - static adapt(configuration: ACLConfiguration): ACLConfiguration { - if (!configuration) return; - - const newConfiguration: ACLConfiguration = ObjectCloner.clone(configuration); - adaptDefaultPolicy(newConfiguration); - adaptAny(newConfiguration); - adaptGroups(newConfiguration); - adaptUsers(newConfiguration); - return newConfiguration; - } -} \ No newline at end of file diff --git a/server/src/lib/configuration/adapters/AuthenticationMethodsAdapter.ts b/server/src/lib/configuration/adapters/AuthenticationMethodsAdapter.ts deleted file mode 100644 index 462d6bc65..000000000 --- a/server/src/lib/configuration/adapters/AuthenticationMethodsAdapter.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { AuthenticationMethodsConfiguration } from "../Configuration"; -import { ObjectCloner } from "../../utils/ObjectCloner"; - -function clone(obj: any): any { - return JSON.parse(JSON.stringify(obj)); -} - -export class AuthenticationMethodsAdapter { - static adapt(authentication_methods: AuthenticationMethodsConfiguration) - : AuthenticationMethodsConfiguration { - if (!authentication_methods) { - return { - default_method: "two_factor", - per_subdomain_methods: {} - }; - } - - const newAuthMethods: AuthenticationMethodsConfiguration - = ObjectCloner.clone(authentication_methods); - - if (!newAuthMethods.default_method) - newAuthMethods.default_method = "two_factor"; - - if (!newAuthMethods.per_subdomain_methods || - newAuthMethods.per_subdomain_methods.constructor !== Object) - newAuthMethods.per_subdomain_methods = {}; - - return newAuthMethods; - } -} diff --git a/server/src/lib/configuration/adapters/TOTPAdapter.ts b/server/src/lib/configuration/adapters/TOTPAdapter.ts deleted file mode 100644 index 198c6ddb2..000000000 --- a/server/src/lib/configuration/adapters/TOTPAdapter.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { TOTPConfiguration } from "../Configuration"; -import { ObjectCloner } from "../../utils/ObjectCloner"; - -const DEFAULT_ISSUER = "authelia.com"; - -export class TOTPAdapter { - static adapt(configuration: TOTPConfiguration): TOTPConfiguration { - const newConfiguration = { - issuer: DEFAULT_ISSUER - }; - - if (!configuration) - return newConfiguration; - - if (configuration && configuration.issuer) - newConfiguration.issuer = configuration.issuer; - - return newConfiguration; - } -} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/AclConfiguration.spec.ts b/server/src/lib/configuration/schema/AclConfiguration.spec.ts new file mode 100644 index 000000000..8c5ef3444 --- /dev/null +++ b/server/src/lib/configuration/schema/AclConfiguration.spec.ts @@ -0,0 +1,14 @@ +import { ACLConfiguration, complete } from "./AclConfiguration"; +import Assert = require("assert"); + +describe("configuration/schema/AclConfiguration", function() { + it("should complete ACLConfiguration", function() { + const configuration: ACLConfiguration = {}; + const newConfiguration = complete(configuration); + + Assert.deepEqual(newConfiguration.default_policy, "allow"); + Assert.deepEqual(newConfiguration.any, []); + Assert.deepEqual(newConfiguration.groups, {}); + Assert.deepEqual(newConfiguration.users, {}); + }); +}); \ No newline at end of file diff --git a/server/src/lib/configuration/schema/AclConfiguration.ts b/server/src/lib/configuration/schema/AclConfiguration.ts new file mode 100644 index 000000000..bba3c4dca --- /dev/null +++ b/server/src/lib/configuration/schema/AclConfiguration.ts @@ -0,0 +1,42 @@ + +export type ACLPolicy = "deny" | "allow"; + +export type ACLRule = { + domain: string; + policy: ACLPolicy; + resources?: string[]; +}; + +export type ACLDefaultRules = ACLRule[]; +export type ACLGroupsRules = { [group: string]: ACLRule[]; }; +export type ACLUsersRules = { [user: string]: ACLRule[]; }; + +export interface ACLConfiguration { + default_policy?: ACLPolicy; + any?: ACLDefaultRules; + groups?: ACLGroupsRules; + users?: ACLUsersRules; +} + +export function complete(configuration: ACLConfiguration): ACLConfiguration { + const newConfiguration: ACLConfiguration = (configuration) + ? JSON.parse(JSON.stringify(configuration)) : {}; + + if (!newConfiguration.default_policy) { + newConfiguration.default_policy = "allow"; + } + + if (!newConfiguration.any) { + newConfiguration.any = []; + } + + if (!newConfiguration.groups) { + newConfiguration.groups = {}; + } + + if (!newConfiguration.users) { + newConfiguration.users = {}; + } + + return newConfiguration; +} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/AuthenticationMethodsConfiguration.spec.ts b/server/src/lib/configuration/schema/AuthenticationMethodsConfiguration.spec.ts new file mode 100644 index 000000000..f39ae671b --- /dev/null +++ b/server/src/lib/configuration/schema/AuthenticationMethodsConfiguration.spec.ts @@ -0,0 +1,12 @@ +import Assert = require("assert"); +import { AuthenticationMethodsConfiguration, complete } from "./AuthenticationMethodsConfiguration"; + +describe("configuration/schema/AuthenticationMethodsConfiguration", function() { + it("should ensure at least one key is provided", function() { + const configuration: AuthenticationMethodsConfiguration = {}; + const newConfiguration = complete(configuration); + + Assert.deepEqual(newConfiguration.default_method, "two_factor"); + Assert.deepEqual(newConfiguration.per_subdomain_methods, []); + }); +}); \ No newline at end of file diff --git a/server/src/lib/configuration/schema/AuthenticationMethodsConfiguration.ts b/server/src/lib/configuration/schema/AuthenticationMethodsConfiguration.ts new file mode 100644 index 000000000..1b454d078 --- /dev/null +++ b/server/src/lib/configuration/schema/AuthenticationMethodsConfiguration.ts @@ -0,0 +1,21 @@ +export type AuthenticationMethod = "two_factor" | "single_factor"; +export type AuthenticationMethodPerSubdomain = { [subdomain: string]: AuthenticationMethod }; + +export interface AuthenticationMethodsConfiguration { + default_method?: AuthenticationMethod; + per_subdomain_methods?: AuthenticationMethodPerSubdomain; +} + +export function complete(configuration: AuthenticationMethodsConfiguration): AuthenticationMethodsConfiguration { + const newConfiguration: AuthenticationMethodsConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {}; + + if (!newConfiguration.default_method) { + newConfiguration.default_method = "two_factor"; + } + + if (!newConfiguration.per_subdomain_methods) { + newConfiguration.per_subdomain_methods = {}; + } + + return newConfiguration; +} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/Configuration.ts b/server/src/lib/configuration/schema/Configuration.ts new file mode 100644 index 000000000..117367f16 --- /dev/null +++ b/server/src/lib/configuration/schema/Configuration.ts @@ -0,0 +1,55 @@ +import { ACLConfiguration, complete as AclConfigurationComplete } from "./AclConfiguration"; +import { AuthenticationMethodsConfiguration, complete as AuthenticationMethodsConfigurationComplete } from "./AuthenticationMethodsConfiguration"; +import { LdapConfiguration, complete as LdapConfigurationComplete } from "./LdapConfiguration"; +import { NotifierConfiguration, complete as NotifierConfigurationComplete } from "./NotifierConfiguration"; +import { RegulationConfiguration, complete as RegulationConfigurationComplete } from "./RegulationConfiguration"; +import { SessionConfiguration, complete as SessionConfigurationComplete } from "./SessionConfiguration"; +import { StorageConfiguration, complete as StorageConfigurationComplete } from "./StorageConfiguration"; +import { TotpConfiguration, complete as TotpConfigurationComplete } from "./TotpConfiguration"; +import { MethodCalculator } from "../../authentication/MethodCalculator"; + +export interface Configuration { + access_control?: ACLConfiguration; + ldap: LdapConfiguration; + authentication_methods?: AuthenticationMethodsConfiguration; + default_redirection_url?: string; + logs_level?: string; + notifier?: NotifierConfiguration; + port?: number; + regulation?: RegulationConfiguration; + session?: SessionConfiguration; + storage?: StorageConfiguration; + totp?: TotpConfiguration; +} + +export function complete(configuration: Configuration): [Configuration, string[]] { + const newConfiguration: Configuration = JSON.parse(JSON.stringify(configuration)); + const errors: string[] = []; + + newConfiguration.access_control = AclConfigurationComplete(newConfiguration.access_control); + newConfiguration.ldap = LdapConfigurationComplete(newConfiguration.ldap); + + newConfiguration.authentication_methods = AuthenticationMethodsConfigurationComplete(newConfiguration.authentication_methods); + + if (!newConfiguration.logs_level) { + newConfiguration.logs_level = "info"; + } + + // In single factor mode, notifier section is optional. + if (!MethodCalculator.isSingleFactorOnlyMode(newConfiguration.authentication_methods)) { + const [notifier, error] = NotifierConfigurationComplete(newConfiguration.notifier); + newConfiguration.notifier = notifier; + if (error) errors.push(error); + } + + if (!newConfiguration.port) { + newConfiguration.port = 8080; + } + + newConfiguration.regulation = RegulationConfigurationComplete(newConfiguration.regulation); + newConfiguration.session = SessionConfigurationComplete(newConfiguration.session); + newConfiguration.storage = StorageConfigurationComplete(newConfiguration.storage); + newConfiguration.totp = TotpConfigurationComplete(newConfiguration.totp); + + return [newConfiguration, errors]; +} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/LdapConfiguration.spec.ts b/server/src/lib/configuration/schema/LdapConfiguration.spec.ts new file mode 100644 index 000000000..cc73d1085 --- /dev/null +++ b/server/src/lib/configuration/schema/LdapConfiguration.spec.ts @@ -0,0 +1,25 @@ +import Assert = require("assert"); +import { LdapConfiguration, complete } from "./LdapConfiguration"; + +describe("configuration/schema/AuthenticationMethodsConfiguration", function() { + it("should ensure at least one key is provided", function() { + const configuration: LdapConfiguration = { + url: "ldap.example.com", + base_dn: "dc=example,dc=com", + user: "admin", + password: "password" + }; + const newConfiguration = complete(configuration); + + Assert.deepEqual(newConfiguration, { + url: "ldap.example.com", + base_dn: "dc=example,dc=com", + user: "admin", + password: "password", + users_filter: "cn={0}", + group_name_attribute: "cn", + groups_filter: "member={dn}", + mail_attribute: "mail" + }); + }); +}); \ No newline at end of file diff --git a/server/src/lib/configuration/schema/LdapConfiguration.ts b/server/src/lib/configuration/schema/LdapConfiguration.ts new file mode 100644 index 000000000..5dacb9390 --- /dev/null +++ b/server/src/lib/configuration/schema/LdapConfiguration.ts @@ -0,0 +1,40 @@ +import Util = require("util"); + +export interface LdapConfiguration { + url: string; + base_dn: string; + + additional_users_dn?: string; + users_filter?: string; + + additional_groups_dn?: string; + groups_filter?: string; + + group_name_attribute?: string; + mail_attribute?: string; + + user: string; // admin username + password: string; // admin password +} + +export function complete(configuration: LdapConfiguration): LdapConfiguration { + const newConfiguration: LdapConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {}; + + if (!newConfiguration.users_filter) { + newConfiguration.users_filter = "cn={0}"; + } + + if (!newConfiguration.groups_filter) { + newConfiguration.groups_filter = "member={dn}"; + } + + if (!newConfiguration.group_name_attribute) { + newConfiguration.group_name_attribute = "cn"; + } + + if (!newConfiguration.mail_attribute) { + newConfiguration.mail_attribute = "mail"; + } + + return newConfiguration; +} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/NotifierConfiguration.spec.ts b/server/src/lib/configuration/schema/NotifierConfiguration.spec.ts new file mode 100644 index 000000000..3ffe940c6 --- /dev/null +++ b/server/src/lib/configuration/schema/NotifierConfiguration.spec.ts @@ -0,0 +1,31 @@ +import Assert = require("assert"); +import { NotifierConfiguration, complete } from "./NotifierConfiguration"; + +describe("configuration/schema/NotifierConfiguration", function() { + it("should ensure at least one key is provided", function() { + const configuration: NotifierConfiguration = {}; + const [newConfiguration, error] = complete(configuration); + + Assert.equal(error, "Notifier must have one of the following keys: 'filesystem', 'email' or 'smtp'"); + }); + + it("should ensure there is no more than one key", function() { + const configuration: NotifierConfiguration = { + smtp: { + host: "smtp.example.com", + port: 25, + secure: false, + sender: "test@example.com" + }, + email: { + username: "test", + password: "test", + sender: "test@example.com", + service: "gmail" + } + }; + const [newConfiguration, error] = complete(configuration); + + Assert.equal(error, "Notifier must have one of the following keys: 'filesystem', 'email' or 'smtp'"); + }); +}); \ No newline at end of file diff --git a/server/src/lib/configuration/schema/NotifierConfiguration.ts b/server/src/lib/configuration/schema/NotifierConfiguration.ts new file mode 100644 index 000000000..497220ef5 --- /dev/null +++ b/server/src/lib/configuration/schema/NotifierConfiguration.ts @@ -0,0 +1,42 @@ + +export interface EmailNotifierConfiguration { + username: string; + password: string; + sender: string; + service: string; +} + +export interface SmtpNotifierConfiguration { + username?: string; + password?: string; + host: string; + port: number; + secure: boolean; + sender: string; +} + +export interface FileSystemNotifierConfiguration { + filename: string; +} + +export interface NotifierConfiguration { + email?: EmailNotifierConfiguration; + smtp?: SmtpNotifierConfiguration; + filesystem?: FileSystemNotifierConfiguration; +} + +export function complete(configuration: NotifierConfiguration): [NotifierConfiguration, string] { + const newConfiguration: NotifierConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {}; + + const ERROR = "Notifier must have one of the following keys: 'filesystem', 'email' or 'smtp'"; + + if (Object.keys(newConfiguration).length != 1) + return [newConfiguration, ERROR]; + + const key = Object.keys(newConfiguration)[0]; + + if (key != "filesystem" && key != "smtp" && key != "email") + return [newConfiguration, ERROR]; + + return [newConfiguration, undefined]; +} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/RegulationConfiguration.spec.ts b/server/src/lib/configuration/schema/RegulationConfiguration.spec.ts new file mode 100644 index 000000000..dce2caf4e --- /dev/null +++ b/server/src/lib/configuration/schema/RegulationConfiguration.spec.ts @@ -0,0 +1,13 @@ +import Assert = require("assert"); +import { RegulationConfiguration, complete } from "./RegulationConfiguration"; + +describe("configuration/schema/RegulationConfiguration", function() { + it("should return default regulation configuration", function() { + const configuration: RegulationConfiguration = {}; + const newConfiguration = complete(configuration); + + Assert.equal(newConfiguration.ban_time, 300); + Assert.equal(newConfiguration.find_time, 120); + Assert.equal(newConfiguration.max_retries, 3); + }); +}); \ No newline at end of file diff --git a/server/src/lib/configuration/schema/RegulationConfiguration.ts b/server/src/lib/configuration/schema/RegulationConfiguration.ts new file mode 100644 index 000000000..117463f43 --- /dev/null +++ b/server/src/lib/configuration/schema/RegulationConfiguration.ts @@ -0,0 +1,23 @@ +export interface RegulationConfiguration { + max_retries?: number; + find_time?: number; + ban_time?: number; +} + +export function complete(configuration: RegulationConfiguration): RegulationConfiguration { + const newConfiguration: RegulationConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {}; + + if (!newConfiguration.max_retries) { + newConfiguration.max_retries = 3; + } + + if (!newConfiguration.find_time) { + newConfiguration.find_time = 120; // seconds + } + + if (!newConfiguration.ban_time) { + newConfiguration.ban_time = 300; // seconds + } + + return newConfiguration; +} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/SessionConfiguration.spec.ts b/server/src/lib/configuration/schema/SessionConfiguration.spec.ts new file mode 100644 index 000000000..b63e7eede --- /dev/null +++ b/server/src/lib/configuration/schema/SessionConfiguration.spec.ts @@ -0,0 +1,15 @@ +import Assert = require("assert"); +import { SessionConfiguration, complete } from "./SessionConfiguration"; + +describe("configuration/schema/SessionConfiguration", function() { + it("should return default regulation configuration", function() { + const configuration: SessionConfiguration = { + domain: "example.com", + secret: "unsecure_secret" + }; + const newConfiguration = complete(configuration); + + Assert.equal(newConfiguration.expiration, 3600000); + Assert.equal(newConfiguration.inactivity, undefined); + }); +}); \ No newline at end of file diff --git a/server/src/lib/configuration/schema/SessionConfiguration.ts b/server/src/lib/configuration/schema/SessionConfiguration.ts new file mode 100644 index 000000000..e628cb0d1 --- /dev/null +++ b/server/src/lib/configuration/schema/SessionConfiguration.ts @@ -0,0 +1,26 @@ +export interface SessionRedisOptions { + host: string; + port: number; +} + +export interface SessionConfiguration { + domain: string; + secret: string; + expiration?: number; + inactivity?: number; + redis?: SessionRedisOptions; +} + +export function complete(configuration: SessionConfiguration): SessionConfiguration { + const newConfiguration: SessionConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {}; + + if (!newConfiguration.expiration) { + newConfiguration.expiration = 3600000; // 1 hour + } + + if (!newConfiguration.inactivity) { + newConfiguration.inactivity = undefined; // disabled + } + + return newConfiguration; +} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/StorageConfiguration.spec.ts b/server/src/lib/configuration/schema/StorageConfiguration.spec.ts new file mode 100644 index 000000000..9d02a11b6 --- /dev/null +++ b/server/src/lib/configuration/schema/StorageConfiguration.spec.ts @@ -0,0 +1,15 @@ +import Assert = require("assert"); +import { StorageConfiguration, complete } from "./StorageConfiguration"; + +describe("configuration/schema/StorageConfiguration", function() { + it("should return default regulation configuration", function() { + const configuration: StorageConfiguration = {}; + const newConfiguration = complete(configuration); + + Assert.deepEqual(newConfiguration, { + local: { + in_memory: true + } + }); + }); +}); \ No newline at end of file diff --git a/server/src/lib/configuration/schema/StorageConfiguration.ts b/server/src/lib/configuration/schema/StorageConfiguration.ts new file mode 100644 index 000000000..9cbc6d170 --- /dev/null +++ b/server/src/lib/configuration/schema/StorageConfiguration.ts @@ -0,0 +1,25 @@ +export interface MongoStorageConfiguration { + url: string; + database: string; +} + +export interface LocalStorageConfiguration { + path?: string; + in_memory?: boolean; +} + +export interface StorageConfiguration { + local?: LocalStorageConfiguration; + mongo?: MongoStorageConfiguration; +} + +export function complete(configuration: StorageConfiguration): StorageConfiguration { + const newConfiguration: StorageConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {}; + + if (!newConfiguration.local && !newConfiguration.mongo) { + newConfiguration.local = { + in_memory: true + }; + } + return newConfiguration; +} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/TotpConfiguration.ts b/server/src/lib/configuration/schema/TotpConfiguration.ts new file mode 100644 index 000000000..683135639 --- /dev/null +++ b/server/src/lib/configuration/schema/TotpConfiguration.ts @@ -0,0 +1,13 @@ +export interface TotpConfiguration { + issuer: string; +} + +export function complete(configuration: TotpConfiguration): TotpConfiguration { + const newConfiguration: TotpConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {}; + + if (!newConfiguration.issuer) { + newConfiguration.issuer = "authelia.com"; + } + + return newConfiguration; +} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/UserDatabaseConfiguration.ts b/server/src/lib/configuration/schema/UserDatabaseConfiguration.ts new file mode 100644 index 000000000..8008b4833 --- /dev/null +++ b/server/src/lib/configuration/schema/UserDatabaseConfiguration.ts @@ -0,0 +1,9 @@ + +export interface UserInfo { + username: string; + password_hash: string; + email: string; + groups?: string[]; +} + +export type UserDatabaseConfiguration = UserInfo[]; \ No newline at end of file diff --git a/server/test/connectors/mongo/MongoClient.test.ts b/server/src/lib/connectors/mongo/MongoClient.spec.ts similarity index 89% rename from server/test/connectors/mongo/MongoClient.test.ts rename to server/src/lib/connectors/mongo/MongoClient.spec.ts index 37ad0c4d6..355e6f028 100644 --- a/server/test/connectors/mongo/MongoClient.test.ts +++ b/server/src/lib/connectors/mongo/MongoClient.spec.ts @@ -1,9 +1,9 @@ import Assert = require("assert"); import Sinon = require("sinon"); import MongoDB = require("mongodb"); -import { MongoClient } from "../../../src/lib/connectors/mongo/MongoClient"; +import { MongoClient } from "./MongoClient"; -describe("MongoClient", function () { +describe("connectors/mongo/MongoClient", function () { let mongoClientConnectStub: Sinon.SinonStub; let mongoDatabase: any; let mongoDatabaseCollectionStub: Sinon.SinonStub; diff --git a/server/test/mocks/connectors/mongo/MongoClientStub.ts b/server/src/lib/connectors/mongo/MongoClientStub.spec.ts similarity index 100% rename from server/test/mocks/connectors/mongo/MongoClientStub.ts rename to server/src/lib/connectors/mongo/MongoClientStub.spec.ts diff --git a/server/test/connectors/mongo/MongoConnector.test.ts b/server/src/lib/connectors/mongo/MongoConnector.spec.ts similarity index 87% rename from server/test/connectors/mongo/MongoConnector.test.ts rename to server/src/lib/connectors/mongo/MongoConnector.spec.ts index 8aebaa9b0..a18026977 100644 --- a/server/test/connectors/mongo/MongoConnector.test.ts +++ b/server/src/lib/connectors/mongo/MongoConnector.spec.ts @@ -2,10 +2,10 @@ import Assert = require("assert"); import Sinon = require("sinon"); import MongoDB = require("mongodb"); import BluebirdPromise = require("bluebird"); -import { IMongoClient } from "../../../src/lib/connectors/mongo/IMongoClient"; -import { MongoConnector } from "../../../src/lib/connectors/mongo/MongoConnector"; +import { IMongoClient } from "./IMongoClient"; +import { MongoConnector } from "./MongoConnector"; -describe("MongoConnector", function () { +describe("connectors/mongo/MongoConnector", function () { let mongoClientConnectStub: Sinon.SinonStub; describe("create", function () { diff --git a/server/test/connectors/mongo/MongoConnectorFactory.test.ts b/server/src/lib/connectors/mongo/MongoConnectorFactory.spec.ts similarity index 65% rename from server/test/connectors/mongo/MongoConnectorFactory.test.ts rename to server/src/lib/connectors/mongo/MongoConnectorFactory.spec.ts index 9d5d9cab4..d82570a8c 100644 --- a/server/test/connectors/mongo/MongoConnectorFactory.test.ts +++ b/server/src/lib/connectors/mongo/MongoConnectorFactory.spec.ts @@ -1,7 +1,7 @@ import Assert = require("assert"); -import { MongoConnectorFactory } from "../../../src/lib/connectors/mongo/MongoConnectorFactory"; +import { MongoConnectorFactory } from "./MongoConnectorFactory"; -describe("MongoConnectorFactory", function () { +describe("connectors/mongo/MongoConnectorFactory", function () { describe("create", function () { it("should create a connector", function () { const factory = new MongoConnectorFactory(); diff --git a/server/test/ldap/Authenticator.test.ts b/server/src/lib/ldap/Authenticator.spec.ts similarity index 92% rename from server/test/ldap/Authenticator.test.ts rename to server/src/lib/ldap/Authenticator.spec.ts index 5300d352e..2a2297569 100644 --- a/server/test/ldap/Authenticator.test.ts +++ b/server/src/lib/ldap/Authenticator.spec.ts @@ -1,16 +1,16 @@ -import { Authenticator } from "../../src/lib/ldap/Authenticator"; -import { LdapConfiguration } from "../../src/lib/configuration/Configuration"; +import { Authenticator } from "./Authenticator"; +import { LdapConfiguration } from "../configuration/schema/LdapConfiguration"; import Sinon = require("sinon"); import BluebirdPromise = require("bluebird"); import Assert = require("assert"); -import { ClientFactoryStub } from "../mocks/ldap/ClientFactoryStub"; -import { ClientStub } from "../mocks/ldap/ClientStub"; +import { ClientFactoryStub } from "./ClientFactoryStub.spec"; +import { ClientStub } from "./ClientStub.spec"; -describe("test ldap authentication", function () { +describe("ldap/Authenticator", function () { const USERNAME = "username"; const PASSWORD = "password"; @@ -31,9 +31,10 @@ describe("test ldap authentication", function () { ldapConfig = { url: "http://localhost:324", - users_dn: "ou=users,dc=example,dc=com", + additional_users_dn: "ou=users", + additional_groups_dn: "ou=groups", + base_dn: "dc=example,dc=com", users_filter: "cn={0}", - groups_dn: "ou=groups,dc=example,dc=com", groups_filter: "member={0}", mail_attribute: "mail", group_name_attribute: "cn", diff --git a/server/src/lib/ldap/Authenticator.ts b/server/src/lib/ldap/Authenticator.ts index a13c68a2f..d804ee590 100644 --- a/server/src/lib/ldap/Authenticator.ts +++ b/server/src/lib/ldap/Authenticator.ts @@ -6,7 +6,7 @@ import { IClientFactory } from "./IClientFactory"; import { GroupsAndEmails } from "./IClient"; import { IAuthenticator } from "./IAuthenticator"; -import { LdapConfiguration } from "../configuration/Configuration"; +import { LdapConfiguration } from "../configuration/schema/LdapConfiguration"; import { EmailsAndGroupsRetriever } from "./EmailsAndGroupsRetriever"; diff --git a/server/test/mocks/ldap/AuthenticatorStub.ts b/server/src/lib/ldap/AuthenticatorStub.spec.ts similarity index 87% rename from server/test/mocks/ldap/AuthenticatorStub.ts rename to server/src/lib/ldap/AuthenticatorStub.spec.ts index 4102b0fe8..1863e45bd 100644 --- a/server/test/mocks/ldap/AuthenticatorStub.ts +++ b/server/src/lib/ldap/AuthenticatorStub.spec.ts @@ -1,6 +1,6 @@ import BluebirdPromise = require("bluebird"); import { IAuthenticator } from "../../../src/lib/ldap/IAuthenticator"; -import { GroupsAndEmails } from "../../../src/lib/ldap/IClient"; +import { GroupsAndEmails } from "./IClient"; import Sinon = require("sinon"); export class AuthenticatorStub implements IAuthenticator { diff --git a/server/test/ldap/Client.test.ts b/server/src/lib/ldap/Client.spec.ts similarity index 86% rename from server/test/ldap/Client.test.ts rename to server/src/lib/ldap/Client.spec.ts index 73073fa2a..b5f705301 100644 --- a/server/test/ldap/Client.test.ts +++ b/server/src/lib/ldap/Client.spec.ts @@ -1,15 +1,15 @@ -import { LdapConfiguration } from "../../src/lib/configuration/Configuration"; -import { Client } from "../../src/lib/ldap/Client"; -import { LdapClientFactoryStub } from "../mocks/ldap/LdapClientFactoryStub"; -import { LdapClientStub } from "../mocks/ldap/LdapClientStub"; +import { LdapConfiguration } from "../configuration/schema/LdapConfiguration"; +import { Client } from "./Client"; +import { LdapClientFactoryStub } from "./LdapClientFactoryStub.spec"; +import { LdapClientStub } from "./LdapClientStub.spec"; import Sinon = require("sinon"); import BluebirdPromise = require("bluebird"); import Assert = require("assert"); import Winston = require("winston"); -describe("test authelia ldap client", function () { +describe("ldap/Client", function () { const USERNAME = "username"; const ADMIN_USER_DN = "cn=admin,dc=example,dc=com"; const ADMIN_PASSWORD = "password"; @@ -17,9 +17,10 @@ describe("test authelia ldap client", function () { it("should replace {0} by username when searching for groups in LDAP", function () { const options: LdapConfiguration = { url: "ldap://ldap", - users_dn: "ou=users,dc=example,dc=com", + additional_users_dn: "ou=users", + additional_groups_dn: "ou=groups", + base_dn: "dc=example,dc=com", users_filter: "cn={0}", - groups_dn: "ou=groups,dc=example,dc=com", groups_filter: "member=cn={0},ou=users,dc=example,dc=com", group_name_attribute: "cn", mail_attribute: "mail", @@ -46,9 +47,10 @@ describe("test authelia ldap client", function () { const USER_DN = "cn=user1,ou=users,dc=example,dc=com"; const options: LdapConfiguration = { url: "ldap://ldap", - users_dn: "ou=users,dc=example,dc=com", + additional_users_dn: "ou=users", + additional_groups_dn: "ou=groups", + base_dn: "dc=example,dc=com", users_filter: "cn={0}", - groups_dn: "ou=groups,dc=example,dc=com", groups_filter: "member={dn}", group_name_attribute: "cn", mail_attribute: "mail", @@ -91,9 +93,10 @@ describe("test authelia ldap client", function () { const USER_DN = "cn=user1,ou=users,dc=example,dc=com"; const options: LdapConfiguration = { url: "ldap://ldap", - users_dn: "ou=users,dc=example,dc=com", + additional_users_dn: "ou=users", + additional_groups_dn: "ou=groups", + base_dn: "dc=example,dc=com", users_filter: "cn={0}", - groups_dn: "ou=groups,dc=example,dc=com", groups_filter: "member={dn}", group_name_attribute: "cn", mail_attribute: "custom_mail", diff --git a/server/src/lib/ldap/Client.ts b/server/src/lib/ldap/Client.ts index 4fa5ae981..7ca215bfb 100644 --- a/server/src/lib/ldap/Client.ts +++ b/server/src/lib/ldap/Client.ts @@ -4,7 +4,7 @@ import { EventEmitter } from "events"; import { IClient, GroupsAndEmails } from "./IClient"; import { ILdapClient } from "./ILdapClient"; import { ILdapClientFactory } from "./ILdapClientFactory"; -import { LdapConfiguration } from "../configuration/Configuration"; +import { LdapConfiguration } from "../configuration/schema/LdapConfiguration"; import { Winston } from "../../../types/Dependencies"; import Util = require("util"); import { HashGenerator } from "../utils/HashGenerator"; @@ -16,6 +16,9 @@ export class Client implements IClient { private logger: Winston; private options: LdapConfiguration; + private groupsSearchBase: string; + private usersSearchBase: string; + constructor(userDN: string, password: string, options: LdapConfiguration, ldapClientFactory: ILdapClientFactory, logger: Winston) { this.options = options; @@ -23,6 +26,14 @@ export class Client implements IClient { this.userDN = userDN; this.password = password; this.ldapClient = ldapClientFactory.create(); + + this.groupsSearchBase = (this.options.additional_groups_dn) + ? Util.format("%s,%s", this.options.additional_groups_dn, this.options.base_dn) + : this.options.base_dn; + + this.usersSearchBase = (this.options.additional_users_dn) + ? Util.format("%s,%s", this.options.additional_users_dn, this.options.base_dn) + : this.options.base_dn; } open(): BluebirdPromise { @@ -64,7 +75,7 @@ export class Client implements IClient { attributes: [that.options.group_name_attribute], filter: groupsFilter }; - return that.ldapClient.searchAsync(that.options.groups_dn, query); + return that.ldapClient.searchAsync(that.groupsSearchBase, query); }) .then(function (docs: { cn: string }[]) { const groups = docs.map((doc: any) => { return doc.cn; }); @@ -85,7 +96,7 @@ export class Client implements IClient { }; that.logger.debug("LDAP: searching for user dn of %s", username); - return that.ldapClient.searchAsync(this.options.users_dn, query) + return that.ldapClient.searchAsync(this.usersSearchBase, query) .then(function (users: { dn: string }[]) { if (users.length > 0) { that.logger.debug("LDAP: retrieved user dn is %s", users[0].dn); diff --git a/server/src/lib/ldap/ClientFactory.ts b/server/src/lib/ldap/ClientFactory.ts index bbef51dae..539e37f8a 100644 --- a/server/src/lib/ldap/ClientFactory.ts +++ b/server/src/lib/ldap/ClientFactory.ts @@ -3,7 +3,7 @@ import { IClient } from "./IClient"; import { Client } from "./Client"; import { SanitizedClient } from "./SanitizedClient"; import { ILdapClientFactory } from "./ILdapClientFactory"; -import { LdapConfiguration } from "../configuration/Configuration"; +import { LdapConfiguration } from "../configuration/schema/LdapConfiguration"; import Ldapjs = require("ldapjs"); import Winston = require("winston"); diff --git a/server/test/mocks/ldap/ClientFactoryStub.ts b/server/src/lib/ldap/ClientFactoryStub.spec.ts similarity index 100% rename from server/test/mocks/ldap/ClientFactoryStub.ts rename to server/src/lib/ldap/ClientFactoryStub.spec.ts diff --git a/server/test/mocks/ldap/ClientStub.ts b/server/src/lib/ldap/ClientStub.spec.ts similarity index 94% rename from server/test/mocks/ldap/ClientStub.ts rename to server/src/lib/ldap/ClientStub.spec.ts index 79e50dafc..fabcebe7a 100644 --- a/server/test/mocks/ldap/ClientStub.ts +++ b/server/src/lib/ldap/ClientStub.spec.ts @@ -1,6 +1,6 @@ import BluebirdPromise = require("bluebird"); -import { IClient, GroupsAndEmails } from "../../../src/lib/ldap/IClient"; +import { IClient, GroupsAndEmails } from "./IClient"; import Sinon = require("sinon"); export class ClientStub implements IClient { diff --git a/server/src/lib/ldap/EmailsAndGroupsRetriever.ts b/server/src/lib/ldap/EmailsAndGroupsRetriever.ts index f17f0368f..0c4f1441f 100644 --- a/server/src/lib/ldap/EmailsAndGroupsRetriever.ts +++ b/server/src/lib/ldap/EmailsAndGroupsRetriever.ts @@ -3,7 +3,7 @@ import exceptions = require("../Exceptions"); import ldapjs = require("ldapjs"); import { Client } from "./Client"; import { IClientFactory } from "./IClientFactory"; -import { LdapConfiguration } from "../configuration/Configuration"; +import { LdapConfiguration } from "../configuration/schema/LdapConfiguration"; import { GroupsAndEmails } from "./IClient"; diff --git a/server/test/ldap/EmailsRetriever.test.ts b/server/src/lib/ldap/EmailsRetriever.spec.ts similarity index 84% rename from server/test/ldap/EmailsRetriever.test.ts rename to server/src/lib/ldap/EmailsRetriever.spec.ts index fcc8846d3..83bd5e77b 100644 --- a/server/test/ldap/EmailsRetriever.test.ts +++ b/server/src/lib/ldap/EmailsRetriever.spec.ts @@ -1,15 +1,15 @@ -import { EmailsRetriever } from "../../src/lib/ldap/EmailsRetriever"; -import { LdapConfiguration } from "../../src/lib/configuration/Configuration"; +import { EmailsRetriever } from "./EmailsRetriever"; +import { LdapConfiguration } from "../configuration/schema/LdapConfiguration"; import Sinon = require("sinon"); import BluebirdPromise = require("bluebird"); import Assert = require("assert"); -import { ClientFactoryStub } from "../mocks/ldap/ClientFactoryStub"; -import { ClientStub } from "../mocks/ldap/ClientStub"; +import { ClientFactoryStub } from "./ClientFactoryStub.spec"; +import { ClientStub } from "./ClientStub.spec"; -describe("test emails retriever", function () { +describe("ldap/EmailsRetriever", function () { const USERNAME = "username"; const ADMIN_USER_DN = "cn=admin,dc=example,dc=com"; const ADMIN_PASSWORD = "password"; @@ -28,8 +28,9 @@ describe("test emails retriever", function () { url: "http://ldap", user: ADMIN_USER_DN, password: ADMIN_PASSWORD, - users_dn: "ou=users,dc=example,dc=com", - groups_dn: "ou=groups,dc=example,dc=com", + additional_users_dn: "ou=users", + additional_groups_dn: "ou=groups", + base_dn: "dc=example,dc=com", group_name_attribute: "cn", groups_filter: "cn={0}", mail_attribute: "mail", diff --git a/server/src/lib/ldap/EmailsRetriever.ts b/server/src/lib/ldap/EmailsRetriever.ts index 34a93a750..21a38ed13 100644 --- a/server/src/lib/ldap/EmailsRetriever.ts +++ b/server/src/lib/ldap/EmailsRetriever.ts @@ -5,7 +5,7 @@ import { Client } from "./Client"; import { IClientFactory } from "./IClientFactory"; import { IEmailsRetriever } from "./IEmailsRetriever"; -import { LdapConfiguration } from "../configuration/Configuration"; +import { LdapConfiguration } from "../configuration/schema/LdapConfiguration"; export class EmailsRetriever implements IEmailsRetriever { diff --git a/server/test/mocks/ldap/EmailsRetrieverStub.ts b/server/src/lib/ldap/EmailsRetrieverStub.spec.ts similarity index 73% rename from server/test/mocks/ldap/EmailsRetrieverStub.ts rename to server/src/lib/ldap/EmailsRetrieverStub.spec.ts index 0e2b87546..442edea00 100644 --- a/server/test/mocks/ldap/EmailsRetrieverStub.ts +++ b/server/src/lib/ldap/EmailsRetrieverStub.spec.ts @@ -1,6 +1,6 @@ import BluebirdPromise = require("bluebird"); -import { IClient } from "../../../src/lib/ldap/IClient"; -import { IEmailsRetriever } from "../../../src/lib/ldap/IEmailsRetriever"; +import { IClient } from "./IClient"; +import { IEmailsRetriever } from "./IEmailsRetriever"; import Sinon = require("sinon"); export class EmailsRetrieverStub implements IEmailsRetriever { diff --git a/server/test/ldap/InputsSanitizer.test.ts b/server/src/lib/ldap/InputsSanitizer.spec.ts similarity index 90% rename from server/test/ldap/InputsSanitizer.test.ts rename to server/src/lib/ldap/InputsSanitizer.spec.ts index d991d0cd8..791d390b0 100644 --- a/server/test/ldap/InputsSanitizer.test.ts +++ b/server/src/lib/ldap/InputsSanitizer.spec.ts @@ -1,7 +1,7 @@ import Assert = require("assert"); -import { InputsSanitizer } from "../../src/lib/ldap/InputsSanitizer"; +import { InputsSanitizer } from "./InputsSanitizer"; -describe("test InputsSanitizer", function () { +describe("ldap/InputsSanitizer", function () { it("should fail when special characters are used", function () { Assert.throws(() => { InputsSanitizer.sanitize("ab,c"); }, Error); Assert.throws(() => { InputsSanitizer.sanitize("a\\bc"); }, Error); diff --git a/server/src/lib/ldap/LdapClientFactory.ts b/server/src/lib/ldap/LdapClientFactory.ts index 39977808f..6e1fe2920 100644 --- a/server/src/lib/ldap/LdapClientFactory.ts +++ b/server/src/lib/ldap/LdapClientFactory.ts @@ -1,7 +1,7 @@ import { ILdapClientFactory } from "./ILdapClientFactory"; import { ILdapClient } from "./ILdapClient"; import { LdapClient } from "./LdapClient"; -import { LdapConfiguration } from "../configuration/Configuration"; +import { LdapConfiguration } from "../configuration/schema/LdapConfiguration"; import Ldapjs = require("ldapjs"); diff --git a/server/test/mocks/ldap/LdapClientFactoryStub.ts b/server/src/lib/ldap/LdapClientFactoryStub.spec.ts similarity index 67% rename from server/test/mocks/ldap/LdapClientFactoryStub.ts rename to server/src/lib/ldap/LdapClientFactoryStub.spec.ts index 01c3573e6..31f26149f 100644 --- a/server/test/mocks/ldap/LdapClientFactoryStub.ts +++ b/server/src/lib/ldap/LdapClientFactoryStub.spec.ts @@ -1,7 +1,7 @@ import Sinon = require("sinon"); import BluebirdPromise = require("bluebird"); -import { ILdapClientFactory } from "../../../src/lib/ldap/ILdapClientFactory"; -import { ILdapClient } from "../../../src/lib/ldap/ILdapClient"; +import { ILdapClientFactory } from "./ILdapClientFactory"; +import { ILdapClient } from "./ILdapClient"; export class LdapClientFactoryStub implements ILdapClientFactory { createStub: Sinon.SinonStub; diff --git a/server/test/mocks/ldap/LdapClientStub.ts b/server/src/lib/ldap/LdapClientStub.spec.ts similarity index 93% rename from server/test/mocks/ldap/LdapClientStub.ts rename to server/src/lib/ldap/LdapClientStub.spec.ts index 9f99392da..c5ea45fff 100644 --- a/server/test/mocks/ldap/LdapClientStub.ts +++ b/server/src/lib/ldap/LdapClientStub.spec.ts @@ -1,6 +1,6 @@ import Sinon = require("sinon"); import BluebirdPromise = require("bluebird"); -import { ILdapClient } from "../../../src/lib/ldap/ILdapClient"; +import { ILdapClient } from "./ILdapClient"; export class LdapClientStub implements ILdapClient { bindAsyncStub: Sinon.SinonStub; diff --git a/server/test/ldap/PasswordUpdater.test.ts b/server/src/lib/ldap/PasswordUpdater.spec.ts similarity index 84% rename from server/test/ldap/PasswordUpdater.test.ts rename to server/src/lib/ldap/PasswordUpdater.spec.ts index e88192614..8afb6ada5 100644 --- a/server/test/ldap/PasswordUpdater.test.ts +++ b/server/src/lib/ldap/PasswordUpdater.spec.ts @@ -1,13 +1,13 @@ import Sinon = require("sinon"); import BluebirdPromise = require("bluebird"); import Assert = require("assert"); -import { PasswordUpdater } from "../../src/lib/ldap/PasswordUpdater"; -import { LdapConfiguration } from "../../src/lib/configuration/Configuration"; -import { ClientFactoryStub } from "../mocks/ldap/ClientFactoryStub"; -import { ClientStub } from "../mocks/ldap/ClientStub"; -import { HashGenerator } from "../../src/lib/utils/HashGenerator"; +import { PasswordUpdater } from "./PasswordUpdater"; +import { LdapConfiguration } from "../configuration/schema/LdapConfiguration"; +import { ClientFactoryStub } from "./ClientFactoryStub.spec"; +import { ClientStub } from "./ClientStub.spec"; +import { HashGenerator } from "../utils/HashGenerator"; -describe("test password update", function () { +describe("ldap/PasswordUpdater", function () { const USERNAME = "username"; const NEW_PASSWORD = "new-password"; @@ -28,8 +28,9 @@ describe("test password update", function () { url: "http://ldap", user: ADMIN_USER_DN, password: ADMIN_PASSWORD, - users_dn: "ou=users,dc=example,dc=com", - groups_dn: "ou=groups,dc=example,dc=com", + additional_users_dn: "ou=users", + additional_groups_dn: "ou=groups", + base_dn: "dc=example,dc=com", group_name_attribute: "cn", groups_filter: "cn={0}", mail_attribute: "mail", diff --git a/server/src/lib/ldap/PasswordUpdater.ts b/server/src/lib/ldap/PasswordUpdater.ts index e492f03b5..03a23ba3b 100644 --- a/server/src/lib/ldap/PasswordUpdater.ts +++ b/server/src/lib/ldap/PasswordUpdater.ts @@ -4,7 +4,7 @@ import ldapjs = require("ldapjs"); import { Client } from "./Client"; import { IPasswordUpdater } from "./IPasswordUpdater"; -import { LdapConfiguration } from "../configuration/Configuration"; +import { LdapConfiguration } from "../configuration/schema/LdapConfiguration"; import { IClientFactory } from "./IClientFactory"; diff --git a/server/test/mocks/ldap/PasswordUpdaterStub.ts b/server/src/lib/ldap/PasswordUpdaterStub.spec.ts similarity index 74% rename from server/test/mocks/ldap/PasswordUpdaterStub.ts rename to server/src/lib/ldap/PasswordUpdaterStub.spec.ts index 9443dddbb..add6465c2 100644 --- a/server/test/mocks/ldap/PasswordUpdaterStub.ts +++ b/server/src/lib/ldap/PasswordUpdaterStub.spec.ts @@ -1,6 +1,6 @@ import BluebirdPromise = require("bluebird"); -import { IClient } from "../../../src/lib/ldap/IClient"; -import { IPasswordUpdater } from "../../../src/lib/ldap/IPasswordUpdater"; +import { IClient } from "./IClient"; +import { IPasswordUpdater } from "./IPasswordUpdater"; import Sinon = require("sinon"); export class PasswordUpdaterStub implements IPasswordUpdater { diff --git a/server/test/ldap/SanitizedClient.test.ts b/server/src/lib/ldap/SanitizedClient.spec.ts similarity index 93% rename from server/test/ldap/SanitizedClient.test.ts rename to server/src/lib/ldap/SanitizedClient.spec.ts index 08aa8c804..6b8009c17 100644 --- a/server/test/ldap/SanitizedClient.test.ts +++ b/server/src/lib/ldap/SanitizedClient.spec.ts @@ -1,8 +1,8 @@ import BluebirdPromise = require("bluebird"); -import { ClientStub } from "../mocks/ldap/ClientStub"; -import { SanitizedClient } from "../../src/lib/ldap/SanitizedClient"; +import { ClientStub } from "./ClientStub.spec"; +import { SanitizedClient } from "./SanitizedClient"; -describe("test SanitizedClient", function () { +describe("ldap/SanitizedClient", function () { let client: SanitizedClient; beforeEach(function () { diff --git a/server/test/mocks/RequestLoggerStub.ts b/server/src/lib/logging/RequestLoggerStub.spec.ts similarity index 88% rename from server/test/mocks/RequestLoggerStub.ts rename to server/src/lib/logging/RequestLoggerStub.spec.ts index 9326ebfcc..b0e375210 100644 --- a/server/test/mocks/RequestLoggerStub.ts +++ b/server/src/lib/logging/RequestLoggerStub.spec.ts @@ -1,6 +1,6 @@ -import { IRequestLogger } from "../../src/lib/logging/IRequestLogger"; +import { IRequestLogger } from "./IRequestLogger"; import Sinon = require("sinon"); -import { RequestLogger } from "../../src/lib/logging/RequestLogger"; +import { RequestLogger } from "./RequestLogger"; import Winston = require("winston"); import Express = require("express"); diff --git a/server/test/notifiers/EMailNotifier.test.ts b/server/src/lib/notifiers/EmailNotifier.spec.ts similarity index 82% rename from server/test/notifiers/EMailNotifier.test.ts rename to server/src/lib/notifiers/EmailNotifier.spec.ts index ca796fca9..8211bbc02 100644 --- a/server/test/notifiers/EMailNotifier.test.ts +++ b/server/src/lib/notifiers/EmailNotifier.spec.ts @@ -2,11 +2,11 @@ import * as sinon from "sinon"; import * as Assert from "assert"; import BluebirdPromise = require("bluebird"); -import { MailSenderStub } from "../mocks/notifiers/MailSenderStub"; -import EMailNotifier = require("../../src/lib/notifiers/EMailNotifier"); +import { MailSenderStub } from "./MailSenderStub.spec"; +import EmailNotifier = require("./EmailNotifier"); -describe("test email notifier", function () { +describe("notifiers/EmailNotifier", function () { it("should send an email to given user", function () { const mailSender = new MailSenderStub(); const options = { @@ -17,7 +17,7 @@ describe("test email notifier", function () { }; mailSender.sendStub.returns(BluebirdPromise.resolve()); - const sender = new EMailNotifier.EMailNotifier(options, mailSender); + const sender = new EmailNotifier.EmailNotifier(options, mailSender); const subject = "subject"; const url = "http://test.com"; @@ -39,7 +39,7 @@ describe("test email notifier", function () { }; mailSender.sendStub.returns(BluebirdPromise.reject(new Error("Failed to send mail"))); - const sender = new EMailNotifier.EMailNotifier(options, mailSender); + const sender = new EmailNotifier.EmailNotifier(options, mailSender); const subject = "subject"; const url = "http://test.com"; diff --git a/server/src/lib/notifiers/EMailNotifier.ts b/server/src/lib/notifiers/EmailNotifier.ts similarity index 80% rename from server/src/lib/notifiers/EMailNotifier.ts rename to server/src/lib/notifiers/EmailNotifier.ts index 5366dfae8..4df7c861e 100644 --- a/server/src/lib/notifiers/EMailNotifier.ts +++ b/server/src/lib/notifiers/EmailNotifier.ts @@ -2,10 +2,10 @@ import * as BluebirdPromise from "bluebird"; import { AbstractEmailNotifier } from "../notifiers/AbstractEmailNotifier"; -import { EmailNotifierConfiguration } from "../configuration/Configuration"; +import { EmailNotifierConfiguration } from "../configuration/schema/NotifierConfiguration"; import { IMailSender } from "./IMailSender"; -export class EMailNotifier extends AbstractEmailNotifier { +export class EmailNotifier extends AbstractEmailNotifier { private mailSender: IMailSender; private sender: string; diff --git a/server/src/lib/notifiers/FileSystemNotifier.ts b/server/src/lib/notifiers/FileSystemNotifier.ts index c5a9f30cd..23f6242c4 100644 --- a/server/src/lib/notifiers/FileSystemNotifier.ts +++ b/server/src/lib/notifiers/FileSystemNotifier.ts @@ -4,7 +4,7 @@ import * as Fs from "fs"; import { INotifier } from "./INotifier"; import { Identity } from "../../../types/Identity"; -import { FileSystemNotifierConfiguration } from "../configuration/Configuration"; +import { FileSystemNotifierConfiguration } from "../configuration/schema/NotifierConfiguration"; export class FileSystemNotifier implements INotifier { private filename: string; diff --git a/server/src/lib/notifiers/IMailSenderBuilder.ts b/server/src/lib/notifiers/IMailSenderBuilder.ts index 59aa677b0..36d4dcdf7 100644 --- a/server/src/lib/notifiers/IMailSenderBuilder.ts +++ b/server/src/lib/notifiers/IMailSenderBuilder.ts @@ -1,5 +1,5 @@ import { IMailSender } from "./IMailSender"; -import { SmtpNotifierConfiguration, EmailNotifierConfiguration } from "../configuration/Configuration"; +import { SmtpNotifierConfiguration, EmailNotifierConfiguration } from "../configuration/schema/NotifierConfiguration"; export interface IMailSenderBuilder { buildEmail(options: EmailNotifierConfiguration): IMailSender; diff --git a/server/test/notifiers/MailSenderBuilder.test.ts b/server/src/lib/notifiers/MailSenderBuilder.spec.ts similarity index 93% rename from server/test/notifiers/MailSenderBuilder.test.ts rename to server/src/lib/notifiers/MailSenderBuilder.spec.ts index e328ac563..41e0db426 100644 --- a/server/test/notifiers/MailSenderBuilder.test.ts +++ b/server/src/lib/notifiers/MailSenderBuilder.spec.ts @@ -1,10 +1,10 @@ -import { MailSenderBuilder } from "../../src/lib/notifiers/MailSenderBuilder"; +import { MailSenderBuilder } from ".//MailSenderBuilder"; import Nodemailer = require("nodemailer"); import Sinon = require("sinon"); import Assert = require("assert"); -describe("test MailSenderBuilder", function() { +describe("notifiers/MailSenderBuilder", function() { let createTransportStub: Sinon.SinonStub; beforeEach(function() { createTransportStub = Sinon.stub(Nodemailer, "createTransport"); diff --git a/server/src/lib/notifiers/MailSenderBuilder.ts b/server/src/lib/notifiers/MailSenderBuilder.ts index 4b22ad743..1d06be52f 100644 --- a/server/src/lib/notifiers/MailSenderBuilder.ts +++ b/server/src/lib/notifiers/MailSenderBuilder.ts @@ -3,7 +3,7 @@ import { IMailSenderBuilder } from "./IMailSenderBuilder"; import { MailSender } from "./MailSender"; import Nodemailer = require("nodemailer"); import NodemailerSmtpTransport = require("nodemailer-smtp-transport"); -import { SmtpNotifierConfiguration, EmailNotifierConfiguration } from "../configuration/Configuration"; +import { SmtpNotifierConfiguration, EmailNotifierConfiguration } from "../configuration/schema/NotifierConfiguration"; export class MailSenderBuilder implements IMailSenderBuilder { private nodemailer: typeof Nodemailer; diff --git a/server/test/mocks/notifiers/MailSenderBuilderStub.ts b/server/src/lib/notifiers/MailSenderBuilderStub.spec.ts similarity index 91% rename from server/test/mocks/notifiers/MailSenderBuilderStub.ts rename to server/src/lib/notifiers/MailSenderBuilderStub.spec.ts index fa38b0684..5b76f6e56 100644 --- a/server/test/mocks/notifiers/MailSenderBuilderStub.ts +++ b/server/src/lib/notifiers/MailSenderBuilderStub.spec.ts @@ -3,7 +3,7 @@ import BluebirdPromise = require("bluebird"); import Nodemailer = require("nodemailer"); import Sinon = require("sinon"); import { IMailSender } from "../../../src/lib/notifiers/IMailSender"; -import { SmtpNotifierConfiguration, EmailNotifierConfiguration } from "../../../src/lib/configuration/Configuration"; +import { SmtpNotifierConfiguration, EmailNotifierConfiguration } from "../../../src/lib/configuration/schema/NotifierConfiguration"; export class MailSenderBuilderStub implements IMailSenderBuilder { buildEmailStub: Sinon.SinonStub; diff --git a/server/test/mocks/notifiers/MailSenderStub.ts b/server/src/lib/notifiers/MailSenderStub.spec.ts similarity index 100% rename from server/test/mocks/notifiers/MailSenderStub.ts rename to server/src/lib/notifiers/MailSenderStub.spec.ts diff --git a/server/test/notifiers/NotifierFactory.test.ts b/server/src/lib/notifiers/NotifierFactory.spec.ts similarity index 71% rename from server/test/notifiers/NotifierFactory.test.ts rename to server/src/lib/notifiers/NotifierFactory.spec.ts index 7ae7d0c38..f15e7667f 100644 --- a/server/test/notifiers/NotifierFactory.test.ts +++ b/server/src/lib/notifiers/NotifierFactory.spec.ts @@ -3,13 +3,13 @@ import * as sinon from "sinon"; import * as BluebirdPromise from "bluebird"; import * as assert from "assert"; -import { NotifierFactory } from "../../src/lib/notifiers/NotifierFactory"; -import { EMailNotifier } from "../../src/lib/notifiers/EMailNotifier"; -import { SmtpNotifier } from "../../src/lib/notifiers/SmtpNotifier"; -import { MailSenderBuilderStub } from "../mocks/notifiers/MailSenderBuilderStub"; +import { NotifierFactory } from "./NotifierFactory"; +import { EmailNotifier } from "./EmailNotifier"; +import { SmtpNotifier } from "./SmtpNotifier"; +import { MailSenderBuilderStub } from "./MailSenderBuilderStub.spec"; -describe("test notifier factory", function () { +describe("notifiers/NotifierFactory", function () { let mailSenderBuilderStub: MailSenderBuilderStub; it("should build a Email Notifier", function () { const options = { @@ -21,7 +21,7 @@ describe("test notifier factory", function () { } }; mailSenderBuilderStub = new MailSenderBuilderStub(); - assert(NotifierFactory.build(options, mailSenderBuilderStub) instanceof EMailNotifier); + assert(NotifierFactory.build(options, mailSenderBuilderStub) instanceof EmailNotifier); }); it("should build a SMTP Notifier", function () { diff --git a/server/src/lib/notifiers/NotifierFactory.ts b/server/src/lib/notifiers/NotifierFactory.ts index c03de76ad..a89155feb 100644 --- a/server/src/lib/notifiers/NotifierFactory.ts +++ b/server/src/lib/notifiers/NotifierFactory.ts @@ -1,10 +1,10 @@ -import { NotifierConfiguration } from "../configuration/Configuration"; +import { NotifierConfiguration } from "../configuration/schema/NotifierConfiguration"; import Nodemailer = require("nodemailer"); import { INotifier } from "./INotifier"; import { FileSystemNotifier } from "./FileSystemNotifier"; -import { EMailNotifier } from "./EMailNotifier"; +import { EmailNotifier } from "./EmailNotifier"; import { SmtpNotifier } from "./SmtpNotifier"; import { IMailSender } from "./IMailSender"; import { IMailSenderBuilder } from "./IMailSenderBuilder"; @@ -13,7 +13,7 @@ export class NotifierFactory { static build(options: NotifierConfiguration, mailSenderBuilder: IMailSenderBuilder): INotifier { if ("email" in options) { const mailSender = mailSenderBuilder.buildEmail(options.email); - return new EMailNotifier(options.email, mailSender); + return new EmailNotifier(options.email, mailSender); } else if ("smtp" in options) { const mailSender = mailSenderBuilder.buildSmtp(options.smtp); diff --git a/server/test/mocks/NotifierStub.ts b/server/src/lib/notifiers/NotifierStub.spec.ts similarity index 85% rename from server/test/mocks/NotifierStub.ts rename to server/src/lib/notifiers/NotifierStub.spec.ts index 94a178e82..f99231b50 100644 --- a/server/test/mocks/NotifierStub.ts +++ b/server/src/lib/notifiers/NotifierStub.spec.ts @@ -1,7 +1,7 @@ import Sinon = require("sinon"); import BluebirdPromise = require("bluebird"); -import { INotifier } from "../../src/lib/notifiers/INotifier"; +import { INotifier } from "./INotifier"; export class NotifierStub implements INotifier { notifyStub: Sinon.SinonStub; diff --git a/server/src/lib/notifiers/SmtpNotifier.ts b/server/src/lib/notifiers/SmtpNotifier.ts index cda174c98..f93a6d4a0 100644 --- a/server/src/lib/notifiers/SmtpNotifier.ts +++ b/server/src/lib/notifiers/SmtpNotifier.ts @@ -4,7 +4,7 @@ import * as BluebirdPromise from "bluebird"; import { IMailSender } from "./IMailSender"; import { AbstractEmailNotifier } from "../notifiers/AbstractEmailNotifier"; -import { SmtpNotifierConfiguration } from "../configuration/Configuration"; +import { SmtpNotifierConfiguration } from "../configuration/schema/NotifierConfiguration"; export class SmtpNotifier extends AbstractEmailNotifier { private mailSender: IMailSender; diff --git a/server/test/regulation/Regulator.test.ts b/server/src/lib/regulation/Regulator.spec.ts similarity index 96% rename from server/test/regulation/Regulator.test.ts rename to server/src/lib/regulation/Regulator.spec.ts index 5f10fd056..f9c6e6086 100644 --- a/server/test/regulation/Regulator.test.ts +++ b/server/src/lib/regulation/Regulator.spec.ts @@ -3,12 +3,12 @@ import Sinon = require("sinon"); import BluebirdPromise = require("bluebird"); import Assert = require("assert"); -import { Regulator } from "../../src/lib/regulation/Regulator"; +import { Regulator } from "./Regulator"; import MockDate = require("mockdate"); -import exceptions = require("../../src/lib/Exceptions"); -import { UserDataStoreStub } from "../mocks/storage/UserDataStoreStub"; +import exceptions = require("../Exceptions"); +import { UserDataStoreStub } from "../storage/UserDataStoreStub.spec"; -describe("test authentication regulator", function () { +describe("regulation/Regulator", function () { const USER1 = "USER1"; const USER2 = "USER2"; let userDataStoreStub: UserDataStoreStub; diff --git a/server/src/lib/regulation/RegulatorStub.spec.ts b/server/src/lib/regulation/RegulatorStub.spec.ts new file mode 100644 index 000000000..ca8a00fb1 --- /dev/null +++ b/server/src/lib/regulation/RegulatorStub.spec.ts @@ -0,0 +1,22 @@ +import Bluebird = require("bluebird"); +import Sinon = require("sinon"); +import { IRegulator } from "./IRegulator"; + + +export class RegulatorStub implements IRegulator { + markStub: Sinon.SinonStub; + regulateStub: Sinon.SinonStub; + + constructor() { + this.markStub = Sinon.stub(); + this.regulateStub = Sinon.stub(); + } + + mark(userId: string, isAuthenticationSuccessful: boolean): Bluebird { + return this.markStub(userId, isAuthenticationSuccessful); + } + + regulate(userId: string): Bluebird { + return this.regulateStub(userId); + } +} diff --git a/server/test/routes/errors/401/get.test.ts b/server/src/lib/routes/error/401/get.spec.ts similarity index 87% rename from server/test/routes/errors/401/get.test.ts rename to server/src/lib/routes/error/401/get.spec.ts index 36766f172..9fdac9c3c 100644 --- a/server/test/routes/errors/401/get.test.ts +++ b/server/src/lib/routes/error/401/get.spec.ts @@ -1,12 +1,12 @@ import Sinon = require("sinon"); import Express = require("express"); import Assert = require("assert"); -import Get401 from "../../../../src/lib/routes/error/401/get"; -import { ServerVariables } from "../../../../src/lib/ServerVariables"; +import Get401 from "./get"; +import { ServerVariables } from "../../../ServerVariables"; import { ServerVariablesMockBuilder, ServerVariablesMock } - from "../../../mocks/ServerVariablesMockBuilder"; + from "../../../ServerVariablesMockBuilder.spec"; -describe("Server error 401", function () { +describe("routes/error/401/get", function () { let vars: ServerVariables; let mocks: ServerVariablesMock; let req: any; diff --git a/server/test/routes/errors/403/get.test.ts b/server/src/lib/routes/error/403/get.spec.ts similarity index 87% rename from server/test/routes/errors/403/get.test.ts rename to server/src/lib/routes/error/403/get.spec.ts index 376acb6a9..22eb84853 100644 --- a/server/test/routes/errors/403/get.test.ts +++ b/server/src/lib/routes/error/403/get.spec.ts @@ -1,12 +1,12 @@ import Sinon = require("sinon"); import Express = require("express"); import Assert = require("assert"); -import Get403 from "../../../../src/lib/routes/error/403/get"; -import { ServerVariables } from "../../../../src/lib/ServerVariables"; +import Get403 from "./get"; +import { ServerVariables } from "../../../ServerVariables"; import { ServerVariablesMockBuilder, ServerVariablesMock } - from "../../../mocks/ServerVariablesMockBuilder"; + from "../../../ServerVariablesMockBuilder.spec"; -describe("Server error 403", function () { +describe("routes/error/403/get", function () { let vars: ServerVariables; let mocks: ServerVariablesMock; let req: any; diff --git a/server/test/routes/errors/404/get.test.ts b/server/src/lib/routes/error/404/get.spec.ts similarity index 79% rename from server/test/routes/errors/404/get.test.ts rename to server/src/lib/routes/error/404/get.spec.ts index fe2838605..73e4e6cef 100644 --- a/server/test/routes/errors/404/get.test.ts +++ b/server/src/lib/routes/error/404/get.spec.ts @@ -1,9 +1,9 @@ import Sinon = require("sinon"); import Express = require("express"); import Assert = require("assert"); -import Get404 from "../../../../src/lib/routes/error/404/get"; +import Get404 from "./get"; -describe("Server error 404", function () { +describe("routes/error/404/get", function () { it("should render the page", function () { const req = {} as Express.Request; const res = { diff --git a/server/test/routes/firstfactor/post.test.ts b/server/src/lib/routes/firstfactor/post.spec.ts similarity index 82% rename from server/test/routes/firstfactor/post.test.ts rename to server/src/lib/routes/firstfactor/post.spec.ts index 6f8ba43cb..e3b726b9f 100644 --- a/server/test/routes/firstfactor/post.test.ts +++ b/server/src/lib/routes/firstfactor/post.spec.ts @@ -2,18 +2,18 @@ import Sinon = require("sinon"); import BluebirdPromise = require("bluebird"); import Assert = require("assert"); -import FirstFactorPost = require("../../../src/lib/routes/firstfactor/post"); -import exceptions = require("../../../src/lib/Exceptions"); -import { AuthenticationSessionHandler } from "../../../src/lib/AuthenticationSessionHandler"; -import { AuthenticationSession } from "../../../types/AuthenticationSession"; -import Endpoints = require("../../../../shared/api"); -import AuthenticationRegulatorMock = require("../../mocks/AuthenticationRegulator"); -import { AccessControllerStub } from "../../mocks/AccessControllerStub"; -import ExpressMock = require("../../mocks/express"); -import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../mocks/ServerVariablesMockBuilder"; -import { ServerVariables } from "../../../src/lib/ServerVariables"; +import FirstFactorPost = require("./post"); +import exceptions = require("../../Exceptions"); +import { AuthenticationSessionHandler } from "../../AuthenticationSessionHandler"; +import { AuthenticationSession } from "../../../../types/AuthenticationSession"; +import Endpoints = require("../../../../../shared/api"); +import AuthenticationRegulatorMock = require("../../regulation/RegulatorStub.spec"); +import { AccessControllerStub } from "../../access_control/AccessControllerStub.spec"; +import ExpressMock = require("../../stubs/express.spec"); +import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../ServerVariablesMockBuilder.spec"; +import { ServerVariables } from "../../ServerVariables"; -describe("test the first factor validation route", function () { +describe("routes/firstfactor/post", function () { let req: ExpressMock.RequestMock; let res: ExpressMock.ResponseMock; let emails: string[]; diff --git a/server/test/routes/password-reset/post.test.ts b/server/src/lib/routes/password-reset/form/post.spec.ts similarity index 83% rename from server/test/routes/password-reset/post.test.ts rename to server/src/lib/routes/password-reset/form/post.spec.ts index 9b86e7a4e..04efe177d 100644 --- a/server/test/routes/password-reset/post.test.ts +++ b/server/src/lib/routes/password-reset/form/post.spec.ts @@ -1,17 +1,17 @@ -import PasswordResetFormPost = require("../../../src/lib/routes/password-reset/form/post"); -import { PasswordUpdater } from "../../../src/lib/ldap/PasswordUpdater"; -import { AuthenticationSessionHandler } from "../../../src/lib/AuthenticationSessionHandler"; -import { AuthenticationSession } from "../../../types/AuthenticationSession"; -import { UserDataStore } from "../../../src/lib/storage/UserDataStore"; +import PasswordResetFormPost = require("./post"); +import { PasswordUpdater } from "../../../ldap/PasswordUpdater"; +import { AuthenticationSessionHandler } from "../../../AuthenticationSessionHandler"; +import { AuthenticationSession } from "../../../../../types/AuthenticationSession"; +import { UserDataStore } from "../../../storage/UserDataStore"; import Sinon = require("sinon"); import Assert = require("assert"); import BluebirdPromise = require("bluebird"); -import ExpressMock = require("../../mocks/express"); -import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../mocks/ServerVariablesMockBuilder"; -import { ServerVariables } from "../../../src/lib/ServerVariables"; +import ExpressMock = require("../../../stubs/express.spec"); +import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../ServerVariablesMockBuilder.spec"; +import { ServerVariables } from "../../../ServerVariables"; -describe("test reset password route", function () { +describe("routes/password-reset/form/post", function () { let req: ExpressMock.RequestMock; let res: ExpressMock.ResponseMock; let vars: ServerVariables; @@ -48,8 +48,9 @@ describe("test reset password route", function () { mail_attribute: "mail", user: "user", password: "password", - users_dn: "ou=users,dc=example,dc=com", - groups_dn: "ou=groups,dc=example,dc=com", + additional_users_dn: "ou=users", + additional_groups_dn: "ou=groups", + base_dn: "dc=example,dc=com", users_filter: "user", group_name_attribute: "cn", groups_filter: "groups" diff --git a/server/test/routes/password-reset/identity/PasswordResetHandler.test.ts b/server/src/lib/routes/password-reset/identity/PasswordResetHandler.spec.ts similarity index 84% rename from server/test/routes/password-reset/identity/PasswordResetHandler.test.ts rename to server/src/lib/routes/password-reset/identity/PasswordResetHandler.spec.ts index f7d906818..34d699cab 100644 --- a/server/test/routes/password-reset/identity/PasswordResetHandler.test.ts +++ b/server/src/lib/routes/password-reset/identity/PasswordResetHandler.spec.ts @@ -1,18 +1,18 @@ import PasswordResetHandler - from "../../../../src/lib/routes/password-reset/identity/PasswordResetHandler"; -import PasswordUpdater = require("../../../../src/lib/ldap/PasswordUpdater"); -import { UserDataStore } from "../../../../src/lib/storage/UserDataStore"; + from "./PasswordResetHandler"; +import PasswordUpdater = require("../../../ldap/PasswordUpdater"); +import { UserDataStore } from "../../../storage/UserDataStore"; import Sinon = require("sinon"); import winston = require("winston"); import assert = require("assert"); import BluebirdPromise = require("bluebird"); -import ExpressMock = require("../../../mocks/express"); +import ExpressMock = require("../../../stubs/express.spec"); import { ServerVariablesMock, ServerVariablesMockBuilder } - from "../../../mocks/ServerVariablesMockBuilder"; -import { ServerVariables } from "../../../../src/lib/ServerVariables"; + from "../../../ServerVariablesMockBuilder.spec"; +import { ServerVariables } from "../../../ServerVariables"; -describe("test reset password identity check", function () { +describe("routes/password-reset/identity/PasswordResetHandler", function () { let req: ExpressMock.RequestMock; let res: ExpressMock.ResponseMock; let mocks: ServerVariablesMock; diff --git a/server/src/lib/routes/password-reset/identity/PasswordResetHandler.ts b/server/src/lib/routes/password-reset/identity/PasswordResetHandler.ts index 2baf2fc8d..5cce78ea2 100644 --- a/server/src/lib/routes/password-reset/identity/PasswordResetHandler.ts +++ b/server/src/lib/routes/password-reset/identity/PasswordResetHandler.ts @@ -4,7 +4,7 @@ import objectPath = require("object-path"); import exceptions = require("../../../Exceptions"); import { Identity } from "../../../../../types/Identity"; -import { IdentityValidable } from "../../../IdentityCheckMiddleware"; +import { IdentityValidable } from "../../../IdentityValidable"; import { PRE_VALIDATION_TEMPLATE } from "../../../IdentityCheckPreValidationTemplate"; import Constants = require("../constants"); import { IRequestLogger } from "../../../logging/IRequestLogger"; diff --git a/server/test/routes/secondfactor/get.test.ts b/server/src/lib/routes/secondfactor/get.spec.ts similarity index 83% rename from server/test/routes/secondfactor/get.test.ts rename to server/src/lib/routes/secondfactor/get.spec.ts index b19733e6b..f7cc8cd33 100644 --- a/server/test/routes/secondfactor/get.test.ts +++ b/server/src/lib/routes/secondfactor/get.spec.ts @@ -1,14 +1,14 @@ -import SecondFactorGet from "../../../src/lib/routes/secondfactor/get"; +import SecondFactorGet from "./get"; import { ServerVariablesMockBuilder, ServerVariablesMock } - from "../../mocks/ServerVariablesMockBuilder"; -import { ServerVariables } from "../../../src/lib/ServerVariables"; + from "../../ServerVariablesMockBuilder.spec"; +import { ServerVariables } from "../../ServerVariables"; import Sinon = require("sinon"); -import ExpressMock = require("../../mocks/express"); +import ExpressMock = require("../../stubs/express.spec"); import Assert = require("assert"); -import Endpoints = require("../../../../shared/api"); +import Endpoints = require("../../../../../shared/api"); import BluebirdPromise = require("bluebird"); -describe("test second factor GET endpoint handler", function () { +describe("routes/secondfactor/get", function () { let mocks: ServerVariablesMock; let vars: ServerVariables; let req: ExpressMock.RequestMock; diff --git a/server/test/routes/secondfactor/redirect.test.ts b/server/src/lib/routes/secondfactor/redirect.spec.ts similarity index 76% rename from server/test/routes/secondfactor/redirect.test.ts rename to server/src/lib/routes/secondfactor/redirect.spec.ts index 2c0dd5d46..ea66e6dca 100644 --- a/server/test/routes/secondfactor/redirect.test.ts +++ b/server/src/lib/routes/secondfactor/redirect.spec.ts @@ -1,11 +1,11 @@ -import Redirect from "../../../src/lib/routes/secondfactor/redirect"; -import ExpressMock = require("../../mocks/express"); +import Redirect from "./redirect"; +import ExpressMock = require("../../stubs/express.spec"); import { ServerVariablesMockBuilder, ServerVariablesMock } -from "../../mocks/ServerVariablesMockBuilder"; -import { ServerVariables } from "../../../src/lib/ServerVariables"; +from "../../ServerVariablesMockBuilder.spec"; +import { ServerVariables } from "../../ServerVariables"; import Assert = require("assert"); -describe("test second factor redirect", function() { +describe("routes/secondfactor/redirect", function() { let req: ExpressMock.RequestMock; let res: ExpressMock.ResponseMock; let mocks: ServerVariablesMock; diff --git a/server/test/routes/secondfactor/totp/register/RegistrationHandler.test.ts b/server/src/lib/routes/secondfactor/totp/identity/RegistrationHandler.spec.ts similarity index 87% rename from server/test/routes/secondfactor/totp/register/RegistrationHandler.test.ts rename to server/src/lib/routes/secondfactor/totp/identity/RegistrationHandler.spec.ts index 1b0aaf34a..78b8ea3ea 100644 --- a/server/test/routes/secondfactor/totp/register/RegistrationHandler.test.ts +++ b/server/src/lib/routes/secondfactor/totp/identity/RegistrationHandler.spec.ts @@ -1,15 +1,15 @@ import Sinon = require("sinon"); -import RegistrationHandler from "../../../../../src/lib/routes/secondfactor/totp/identity/RegistrationHandler"; -import { Identity } from "../../../../../types/Identity"; -import { UserDataStore } from "../../../../../src/lib/storage/UserDataStore"; +import RegistrationHandler from "./RegistrationHandler"; +import { Identity } from "../../../../../../types/Identity"; +import { UserDataStore } from "../../../../storage/UserDataStore"; import BluebirdPromise = require("bluebird"); -import ExpressMock = require("../../../../mocks/express"); +import ExpressMock = require("../../../../stubs/express.spec"); import { ServerVariablesMock, ServerVariablesMockBuilder } - from "../../../../mocks/ServerVariablesMockBuilder"; -import { ServerVariables } from "../../../../../src/lib/ServerVariables"; + from "../../../../ServerVariablesMockBuilder.spec"; +import { ServerVariables } from "../../../../ServerVariables"; import Assert = require("assert"); -describe("test totp register", function () { +describe("routes/secondfactor/totp/identity/RegistrationHandler", function () { let req: ExpressMock.RequestMock; let res: ExpressMock.ResponseMock; let mocks: ServerVariablesMock; diff --git a/server/src/lib/routes/secondfactor/totp/identity/RegistrationHandler.ts b/server/src/lib/routes/secondfactor/totp/identity/RegistrationHandler.ts index d8394aadb..b39b6d045 100644 --- a/server/src/lib/routes/secondfactor/totp/identity/RegistrationHandler.ts +++ b/server/src/lib/routes/secondfactor/totp/identity/RegistrationHandler.ts @@ -4,7 +4,7 @@ import BluebirdPromise = require("bluebird"); import objectPath = require("object-path"); import { Identity } from "../../../../../../types/Identity"; -import { IdentityValidable } from "../../../../IdentityCheckMiddleware"; +import { IdentityValidable } from "../../../../IdentityValidable"; import { PRE_VALIDATION_TEMPLATE } from "../../../../IdentityCheckPreValidationTemplate"; import Constants = require("../constants"); import Endpoints = require("../../../../../../../shared/api"); @@ -16,18 +16,18 @@ import { IRequestLogger } from "../../../../logging/IRequestLogger"; import { IUserDataStore } from "../../../../storage/IUserDataStore"; import { ITotpHandler } from "../../../../authentication/totp/ITotpHandler"; import { TOTPSecret } from "../../../../../../types/TOTPSecret"; -import { TOTPConfiguration } from "../../../../configuration/Configuration"; +import { TotpConfiguration } from "../../../../configuration/schema/TotpConfiguration"; export default class RegistrationHandler implements IdentityValidable { private logger: IRequestLogger; private userDataStore: IUserDataStore; private totp: ITotpHandler; - private configuration: TOTPConfiguration; + private configuration: TotpConfiguration; constructor(logger: IRequestLogger, userDataStore: IUserDataStore, - totp: ITotpHandler, configuration: TOTPConfiguration) { + totp: ITotpHandler, configuration: TotpConfiguration) { this.logger = logger; this.userDataStore = userDataStore; this.totp = totp; diff --git a/server/test/routes/secondfactor/totp/sign/post.test.ts b/server/src/lib/routes/secondfactor/totp/sign/post.spec.ts similarity index 75% rename from server/test/routes/secondfactor/totp/sign/post.test.ts rename to server/src/lib/routes/secondfactor/totp/sign/post.spec.ts index ddf1d26cf..651f7d77f 100644 --- a/server/test/routes/secondfactor/totp/sign/post.test.ts +++ b/server/src/lib/routes/secondfactor/totp/sign/post.spec.ts @@ -2,17 +2,17 @@ import BluebirdPromise = require("bluebird"); import Sinon = require("sinon"); import Assert = require("assert"); -import Exceptions = require("../../../../../src/lib/Exceptions"); -import { AuthenticationSessionHandler } from "../../../../../src/lib/AuthenticationSessionHandler"; -import { AuthenticationSession } from "../../../../../types/AuthenticationSession"; -import SignPost = require("../../../../../src/lib/routes/secondfactor/totp/sign/post"); -import { ServerVariables } from "../../../../../src/lib/ServerVariables"; +import Exceptions = require("../../../../Exceptions"); +import { AuthenticationSessionHandler } from "../../../../AuthenticationSessionHandler"; +import { AuthenticationSession } from "../../../../../../types/AuthenticationSession"; +import SignPost = require("./post"); +import { ServerVariables } from "../../../../ServerVariables"; -import ExpressMock = require("../../../../mocks/express"); -import { UserDataStoreStub } from "../../../../mocks/storage/UserDataStoreStub"; -import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../../mocks/ServerVariablesMockBuilder"; +import ExpressMock = require("../../../../stubs/express.spec"); +import { UserDataStoreStub } from "../../../../storage/UserDataStoreStub.spec"; +import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../../ServerVariablesMockBuilder.spec"; -describe("test totp route", function () { +describe("routes/secondfactor/totp/sign/post", function () { let req: ExpressMock.RequestMock; let res: ExpressMock.ResponseMock; let authSession: AuthenticationSession; diff --git a/server/src/lib/routes/secondfactor/totp/sign/post.ts b/server/src/lib/routes/secondfactor/totp/sign/post.ts index 45bbec94f..1d62b5497 100644 --- a/server/src/lib/routes/secondfactor/totp/sign/post.ts +++ b/server/src/lib/routes/secondfactor/totp/sign/post.ts @@ -1,11 +1,9 @@ +import Bluebird = require("bluebird"); +import Express = require("express"); -import exceptions = require("../../../../Exceptions"); -import objectPath = require("object-path"); -import express = require("express"); import { TOTPSecretDocument } from "../../../../storage/TOTPSecretDocument"; -import BluebirdPromise = require("bluebird"); import Endpoints = require("../../../../../../../shared/api"); -import redirect from "../../redirect"; +import Redirect from "../../redirect"; import ErrorReplies = require("../../../../ErrorReplies"); import { AuthenticationSessionHandler } from "../../../../AuthenticationSessionHandler"; import { AuthenticationSession } from "../../../../../../types/AuthenticationSession"; @@ -15,11 +13,11 @@ import { ServerVariables } from "../../../../ServerVariables"; const UNAUTHORIZED_MESSAGE = "Unauthorized access"; export default function (vars: ServerVariables) { - function handler(req: express.Request, res: express.Response): BluebirdPromise { + function handler(req: Express.Request, res: Express.Response): Bluebird { let authSession: AuthenticationSession; const token = req.body.token; - return new BluebirdPromise(function (resolve, reject) { + return new Bluebird(function (resolve, reject) { authSession = AuthenticationSessionHandler.get(req, vars.logger); vars.logger.info(req, "Initiate TOTP validation for user \"%s\".", authSession.userid); resolve(); @@ -29,12 +27,12 @@ export default function (vars: ServerVariables) { }) .then(function (doc: TOTPSecretDocument) { if (!vars.totpHandler.validate(token, doc.secret.base32)) - return BluebirdPromise.reject(new Error("Invalid TOTP token.")); + return Bluebird.reject(new Error("Invalid TOTP token.")); vars.logger.debug(req, "TOTP validation succeeded."); authSession.second_factor = true; - redirect(vars)(req, res); - return BluebirdPromise.resolve(); + Redirect(vars)(req, res); + return Bluebird.resolve(); }) .catch(ErrorReplies.replyWithError200(req, res, vars.logger, UserMessages.OPERATION_FAILED)); diff --git a/server/test/routes/secondfactor/u2f/identity/RegistrationHandler.test.ts b/server/src/lib/routes/secondfactor/u2f/identity/RegistrationHandler.spec.ts similarity index 86% rename from server/test/routes/secondfactor/u2f/identity/RegistrationHandler.test.ts rename to server/src/lib/routes/secondfactor/u2f/identity/RegistrationHandler.spec.ts index d10268f34..a54bfbfe6 100644 --- a/server/test/routes/secondfactor/u2f/identity/RegistrationHandler.test.ts +++ b/server/src/lib/routes/secondfactor/u2f/identity/RegistrationHandler.spec.ts @@ -2,14 +2,14 @@ import Sinon = require("sinon"); import Assert = require("assert"); import BluebirdPromise = require("bluebird"); -import { Identity } from "../../../../../types/Identity"; -import RegistrationHandler from "../../../../../src/lib/routes/secondfactor/u2f/identity/RegistrationHandler"; -import ExpressMock = require("../../../../mocks/express"); -import { UserDataStoreStub } from "../../../../mocks/storage/UserDataStoreStub"; -import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../../mocks/ServerVariablesMockBuilder"; -import { ServerVariables } from "../../../../../src/lib/ServerVariables"; +import { Identity } from "../../../../../../types/Identity"; +import RegistrationHandler from "./RegistrationHandler"; +import ExpressMock = require("../../../../stubs/express.spec"); +import { UserDataStoreStub } from "../../../../storage/UserDataStoreStub.spec"; +import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../../ServerVariablesMockBuilder.spec"; +import { ServerVariables } from "../../../../ServerVariables"; -describe("test U2F register handler", function () { +describe("routes/secondfactor/u2f/identity/RegistrationHandler", function () { let req: ExpressMock.RequestMock; let res: ExpressMock.ResponseMock; let mocks: ServerVariablesMock; diff --git a/server/src/lib/routes/secondfactor/u2f/identity/RegistrationHandler.ts b/server/src/lib/routes/secondfactor/u2f/identity/RegistrationHandler.ts index 06fd44da8..bc4713c77 100644 --- a/server/src/lib/routes/secondfactor/u2f/identity/RegistrationHandler.ts +++ b/server/src/lib/routes/secondfactor/u2f/identity/RegistrationHandler.ts @@ -3,7 +3,7 @@ import BluebirdPromise = require("bluebird"); import express = require("express"); import objectPath = require("object-path"); -import { IdentityValidable } from "../../../../IdentityCheckMiddleware"; +import { IdentityValidable } from "../../../../IdentityValidable"; import { Identity } from "../../../../../../types/Identity"; import { PRE_VALIDATION_TEMPLATE } from "../../../../IdentityCheckPreValidationTemplate"; import FirstFactorValidator = require("../../../../FirstFactorValidator"); diff --git a/server/test/routes/secondfactor/u2f/register/post.test.ts b/server/src/lib/routes/secondfactor/u2f/register/post.spec.ts similarity index 88% rename from server/test/routes/secondfactor/u2f/register/post.test.ts rename to server/src/lib/routes/secondfactor/u2f/register/post.spec.ts index 59ee8a761..de3347a21 100644 --- a/server/test/routes/secondfactor/u2f/register/post.test.ts +++ b/server/src/lib/routes/secondfactor/u2f/register/post.spec.ts @@ -2,16 +2,16 @@ import sinon = require("sinon"); import BluebirdPromise = require("bluebird"); import assert = require("assert"); -import U2FRegisterPost = require("../../../../../src/lib/routes/secondfactor/u2f/register/post"); -import { AuthenticationSessionHandler } from "../../../../../src/lib/AuthenticationSessionHandler"; -import { AuthenticationSession } from "../../../../../types/AuthenticationSession"; -import ExpressMock = require("../../../../mocks/express"); -import { UserDataStoreStub } from "../../../../mocks/storage/UserDataStoreStub"; -import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../../../mocks/ServerVariablesMockBuilder"; -import { ServerVariables } from "../../../../../src/lib/ServerVariables"; +import U2FRegisterPost = require("./post"); +import { AuthenticationSessionHandler } from "../../../../AuthenticationSessionHandler"; +import { AuthenticationSession } from "../../../../../../types/AuthenticationSession"; +import ExpressMock = require("../../../../stubs/express.spec"); +import { UserDataStoreStub } from "../../../../storage/UserDataStoreStub.spec"; +import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../../../ServerVariablesMockBuilder.spec"; +import { ServerVariables } from "../../../../ServerVariables"; -describe("test u2f routes: register", function () { +describe("routes/secondfactor/u2f/register/post", function () { let req: ExpressMock.RequestMock; let res: ExpressMock.ResponseMock; let mocks: ServerVariablesMock; diff --git a/server/test/routes/secondfactor/u2f/register_request/get.test.ts b/server/src/lib/routes/secondfactor/u2f/register_request/get.spec.ts similarity index 85% rename from server/test/routes/secondfactor/u2f/register_request/get.test.ts rename to server/src/lib/routes/secondfactor/u2f/register_request/get.spec.ts index 9617e24bb..a207c9109 100644 --- a/server/test/routes/secondfactor/u2f/register_request/get.test.ts +++ b/server/src/lib/routes/secondfactor/u2f/register_request/get.spec.ts @@ -2,13 +2,13 @@ import sinon = require("sinon"); import BluebirdPromise = require("bluebird"); import Assert = require("assert"); -import U2FRegisterRequestGet = require("../../../../../src/lib/routes/secondfactor/u2f/register_request/get"); -import ExpressMock = require("../../../../mocks/express"); -import { UserDataStoreStub } from "../../../../mocks/storage/UserDataStoreStub"; -import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../../../mocks/ServerVariablesMockBuilder"; -import { ServerVariables } from "../../../../../src/lib/ServerVariables"; +import U2FRegisterRequestGet = require("./get"); +import ExpressMock = require("../../../../stubs/express.spec"); +import { UserDataStoreStub } from "../../../../storage/UserDataStoreStub.spec"; +import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../../../ServerVariablesMockBuilder.spec"; +import { ServerVariables } from "../../../../ServerVariables"; -describe("test u2f routes: register_request", function () { +describe("routes/secondfactor/u2f/register_request/get", function () { let req: ExpressMock.RequestMock; let res: ExpressMock.ResponseMock; let mocks: ServerVariablesMock; diff --git a/server/test/routes/secondfactor/u2f/sign/post.test.ts b/server/src/lib/routes/secondfactor/u2f/sign/post.spec.ts similarity index 86% rename from server/test/routes/secondfactor/u2f/sign/post.test.ts rename to server/src/lib/routes/secondfactor/u2f/sign/post.spec.ts index 942d9dbfa..034a73ebd 100644 --- a/server/test/routes/secondfactor/u2f/sign/post.test.ts +++ b/server/src/lib/routes/secondfactor/u2f/sign/post.spec.ts @@ -2,16 +2,16 @@ import sinon = require("sinon"); import BluebirdPromise = require("bluebird"); import Assert = require("assert"); -import U2FSignPost = require("../../../../../src/lib/routes/secondfactor/u2f/sign/post"); -import { ServerVariables } from "../../../../../src/lib/ServerVariables"; +import U2FSignPost = require("./post"); +import { ServerVariables } from "../../../../ServerVariables"; import winston = require("winston"); -import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../../../mocks/ServerVariablesMockBuilder"; -import ExpressMock = require("../../../../mocks/express"); -import U2FMock = require("../../../../mocks/u2f"); +import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../../../ServerVariablesMockBuilder.spec"; +import ExpressMock = require("../../../../stubs/express.spec"); +import U2FMock = require("../../../../stubs/u2f.spec"); import U2f = require("u2f"); -describe("test u2f routes: sign", function () { +describe("routes/secondfactor/u2f/sign/post", function () { let req: ExpressMock.RequestMock; let res: ExpressMock.ResponseMock; let mocks: ServerVariablesMock; diff --git a/server/test/routes/secondfactor/u2f/sign_request/get.test.ts b/server/src/lib/routes/secondfactor/u2f/sign_request/get.spec.ts similarity index 76% rename from server/test/routes/secondfactor/u2f/sign_request/get.test.ts rename to server/src/lib/routes/secondfactor/u2f/sign_request/get.spec.ts index 49e7cf11e..db2fb0c31 100644 --- a/server/test/routes/secondfactor/u2f/sign_request/get.test.ts +++ b/server/src/lib/routes/secondfactor/u2f/sign_request/get.spec.ts @@ -2,17 +2,17 @@ import sinon = require("sinon"); import BluebirdPromise = require("bluebird"); import assert = require("assert"); -import U2FSignRequestGet = require("../../../../../src/lib/routes/secondfactor/u2f/sign_request/get"); -import ExpressMock = require("../../../../mocks/express"); -import { UserDataStoreStub } from "../../../../mocks/storage/UserDataStoreStub"; -import U2FMock = require("../../../../mocks/u2f"); +import U2FSignRequestGet = require("./get"); +import ExpressMock = require("../../../../stubs/express.spec"); +import { UserDataStoreStub } from "../../../../storage/UserDataStoreStub.spec"; +import U2FMock = require("../../../../stubs/u2f.spec"); import U2f = require("u2f"); -import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../../mocks/ServerVariablesMockBuilder"; -import { ServerVariables } from "../../../../../src/lib/ServerVariables"; +import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../../ServerVariablesMockBuilder.spec"; +import { ServerVariables } from "../../../../ServerVariables"; -import { SignMessage } from "../../../../../../shared/SignMessage"; +import { SignMessage } from "../../../../../../../shared/SignMessage"; -describe("test u2f routes: sign_request", function () { +describe("routes/secondfactor/u2f/sign_request/get", function () { let req: ExpressMock.RequestMock; let res: ExpressMock.ResponseMock; let mocks: ServerVariablesMock; diff --git a/server/test/routes/verify/get.test.ts b/server/src/lib/routes/verify/get.spec.ts similarity index 95% rename from server/test/routes/verify/get.test.ts rename to server/src/lib/routes/verify/get.spec.ts index 2baa49c3b..cb8cb5869 100644 --- a/server/test/routes/verify/get.test.ts +++ b/server/src/lib/routes/verify/get.spec.ts @@ -1,18 +1,17 @@ import Assert = require("assert"); -import VerifyGet = require("../../../src/lib/routes/verify/get"); -import { AuthenticationSessionHandler } from "../../../src/lib/AuthenticationSessionHandler"; -import { AuthenticationSession } from "../../../types/AuthenticationSession"; -import { AuthenticationMethodsConfiguration } from "../../../src/lib/configuration/Configuration"; +import VerifyGet = require("./get"); +import { AuthenticationSessionHandler } from "../../AuthenticationSessionHandler"; +import { AuthenticationSession } from "../../../../types/AuthenticationSession"; import Sinon = require("sinon"); import winston = require("winston"); import BluebirdPromise = require("bluebird"); import express = require("express"); -import ExpressMock = require("../../mocks/express"); -import { ServerVariables } from "../../../src/lib/ServerVariables"; -import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../mocks/ServerVariablesMockBuilder"; +import ExpressMock = require("../../stubs/express.spec"); +import { ServerVariables } from "../../ServerVariables"; +import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../ServerVariablesMockBuilder.spec"; -describe("test /api/verify endpoint", function () { +describe("routes/verify/get", function () { let req: ExpressMock.RequestMock; let res: ExpressMock.ResponseMock; let mocks: ServerVariablesMock; diff --git a/server/src/lib/routes/verify/get_session_cookie.ts b/server/src/lib/routes/verify/get_session_cookie.ts index 6571e8fe8..8b144cd95 100644 --- a/server/src/lib/routes/verify/get_session_cookie.ts +++ b/server/src/lib/routes/verify/get_session_cookie.ts @@ -4,7 +4,7 @@ import Util = require("util"); import ObjectPath = require("object-path"); import Exceptions = require("../../Exceptions"); -import { AppConfiguration } from "../../configuration/Configuration"; +import { Configuration } from "../../configuration/schema/Configuration"; import Constants = require("../../../../../shared/constants"); import { DomainExtractor } from "../../utils/DomainExtractor"; import { ServerVariables } from "../../ServerVariables"; @@ -21,7 +21,7 @@ const SECOND_FACTOR_NOT_VALIDATED_MESSAGE = "Second factor not yet validated"; function verify_inactivity(req: Express.Request, authSession: AuthenticationSession, - configuration: AppConfiguration, logger: IRequestLogger) + configuration: Configuration, logger: IRequestLogger) : BluebirdPromise { // If inactivity is not specified, then inactivity timeout does not apply diff --git a/server/test/mocks/storage/CollectionFactoryStub.ts b/server/src/lib/storage/CollectionFactoryStub.spec.ts similarity index 70% rename from server/test/mocks/storage/CollectionFactoryStub.ts rename to server/src/lib/storage/CollectionFactoryStub.spec.ts index 947be55f5..17f8bb021 100644 --- a/server/test/mocks/storage/CollectionFactoryStub.ts +++ b/server/src/lib/storage/CollectionFactoryStub.spec.ts @@ -1,7 +1,7 @@ import BluebirdPromise = require("bluebird"); import Sinon = require("sinon"); -import { ICollection } from "../../../src/lib/storage/ICollection"; -import { ICollectionFactory } from "../../../src/lib/storage/ICollectionFactory"; +import { ICollection } from "./ICollection"; +import { ICollectionFactory } from "./ICollectionFactory"; export class CollectionFactoryStub implements ICollectionFactory { buildStub: Sinon.SinonStub; diff --git a/server/test/mocks/storage/CollectionStub.ts b/server/src/lib/storage/CollectionStub.spec.ts similarity index 94% rename from server/test/mocks/storage/CollectionStub.ts rename to server/src/lib/storage/CollectionStub.spec.ts index 05dc76ba6..42895d672 100644 --- a/server/test/mocks/storage/CollectionStub.ts +++ b/server/src/lib/storage/CollectionStub.spec.ts @@ -1,6 +1,6 @@ import BluebirdPromise = require("bluebird"); import Sinon = require("sinon"); -import { ICollection } from "../../../src/lib/storage/ICollection"; +import { ICollection } from "./ICollection"; export class CollectionStub implements ICollection { findStub: Sinon.SinonStub; diff --git a/server/test/storage/UserDataStore.test.ts b/server/src/lib/storage/UserDataStore.spec.ts similarity index 94% rename from server/test/storage/UserDataStore.test.ts rename to server/src/lib/storage/UserDataStore.spec.ts index c43d52a1d..66fb85461 100644 --- a/server/test/storage/UserDataStore.test.ts +++ b/server/src/lib/storage/UserDataStore.spec.ts @@ -4,14 +4,14 @@ import * as Sinon from "sinon"; import * as MockDate from "mockdate"; import BluebirdPromise = require("bluebird"); -import { UserDataStore } from "../../src/lib/storage/UserDataStore"; -import { TOTPSecret } from "../../types/TOTPSecret"; -import { U2FRegistration } from "../../types/U2FRegistration"; -import { AuthenticationTraceDocument } from "../../src/lib/storage/AuthenticationTraceDocument"; -import { CollectionStub } from "../mocks/storage/CollectionStub"; -import { CollectionFactoryStub } from "../mocks/storage/CollectionFactoryStub"; +import { UserDataStore } from "./UserDataStore"; +import { TOTPSecret } from "../../../types/TOTPSecret"; +import { U2FRegistration } from "../../../types/U2FRegistration"; +import { AuthenticationTraceDocument } from "./AuthenticationTraceDocument"; +import { CollectionStub } from "./CollectionStub.spec"; +import { CollectionFactoryStub } from "./CollectionFactoryStub.spec"; -describe("test user data store", function () { +describe("storage/UserDataStore", function () { let factory: CollectionFactoryStub; let collection: CollectionStub; let userId: string; diff --git a/server/test/mocks/storage/UserDataStoreStub.ts b/server/src/lib/storage/UserDataStoreStub.spec.ts similarity index 85% rename from server/test/mocks/storage/UserDataStoreStub.ts rename to server/src/lib/storage/UserDataStoreStub.spec.ts index 41fa0bb97..5ea27a2de 100644 --- a/server/test/mocks/storage/UserDataStoreStub.ts +++ b/server/src/lib/storage/UserDataStoreStub.spec.ts @@ -1,14 +1,13 @@ import Sinon = require("sinon"); import BluebirdPromise = require("bluebird"); -import { TOTPSecretDocument } from "../../../src/lib/storage/TOTPSecretDocument"; -import { U2FRegistrationDocument } from "../../../src/lib/storage/U2FRegistrationDocument"; +import { TOTPSecretDocument } from "./TOTPSecretDocument"; +import { U2FRegistrationDocument } from "./U2FRegistrationDocument"; import { U2FRegistration } from "../../../types/U2FRegistration"; import { TOTPSecret } from "../../../types/TOTPSecret"; -import { AuthenticationTraceDocument } from "../../../src/lib/storage/AuthenticationTraceDocument"; -import { IdentityValidationDocument } from "../../../src/lib/storage/IdentityValidationDocument"; - -import { IUserDataStore } from "../../../src/lib/storage/IUserDataStore"; +import { AuthenticationTraceDocument } from "./AuthenticationTraceDocument"; +import { IdentityValidationDocument } from "./IdentityValidationDocument"; +import { IUserDataStore } from "./IUserDataStore"; export class UserDataStoreStub implements IUserDataStore { saveU2FRegistrationStub: Sinon.SinonStub; diff --git a/server/test/storage/mongo/MongoCollection.test.ts b/server/src/lib/storage/mongo/MongoCollection.spec.ts similarity index 94% rename from server/test/storage/mongo/MongoCollection.test.ts rename to server/src/lib/storage/mongo/MongoCollection.spec.ts index bce9026c6..49208b5df 100644 --- a/server/test/storage/mongo/MongoCollection.test.ts +++ b/server/src/lib/storage/mongo/MongoCollection.spec.ts @@ -2,10 +2,10 @@ import Assert = require("assert"); import Sinon = require("sinon"); import MongoDB = require("mongodb"); import BluebirdPromise = require("bluebird"); -import { MongoClientStub } from "../../mocks/connectors/mongo/MongoClientStub"; -import { MongoCollection } from "../../../src/lib/storage/mongo/MongoCollection"; +import { MongoClientStub } from "../../connectors/mongo/MongoClientStub.spec"; +import { MongoCollection } from "./MongoCollection"; -describe("MongoCollection", function () { +describe("storage/mongo/MongoCollection", function () { let mongoCollectionStub: any; let findStub: Sinon.SinonStub; let findOneStub: Sinon.SinonStub; diff --git a/server/test/storage/mongo/MongoCollectionFactory.test.ts b/server/src/lib/storage/mongo/MongoCollectionFactory.spec.ts similarity index 66% rename from server/test/storage/mongo/MongoCollectionFactory.test.ts rename to server/src/lib/storage/mongo/MongoCollectionFactory.spec.ts index eab3da9a6..bd959cacb 100644 --- a/server/test/storage/mongo/MongoCollectionFactory.test.ts +++ b/server/src/lib/storage/mongo/MongoCollectionFactory.spec.ts @@ -1,9 +1,9 @@ import Assert = require("assert"); import Sinon = require("sinon"); -import { MongoClientStub } from "../../mocks/connectors/mongo/MongoClientStub"; -import { MongoCollectionFactory } from "../../../src/lib/storage/mongo/MongoCollectionFactory"; +import { MongoClientStub } from "../../connectors/mongo/MongoClientStub.spec"; +import { MongoCollectionFactory } from "./MongoCollectionFactory"; -describe("MongoCollectionFactory", function () { +describe("storage/mongo/MongoCollectionFactory", function () { let mongoClient: MongoClientStub; before(function() { diff --git a/server/test/storage/nedb/NedbCollection.test.ts b/server/src/lib/storage/nedb/NedbCollection.spec.ts similarity index 96% rename from server/test/storage/nedb/NedbCollection.test.ts rename to server/src/lib/storage/nedb/NedbCollection.spec.ts index 16c79b4ef..a69962b67 100644 --- a/server/test/storage/nedb/NedbCollection.test.ts +++ b/server/src/lib/storage/nedb/NedbCollection.spec.ts @@ -1,9 +1,9 @@ import Sinon = require("sinon"); import Assert = require("assert"); -import { NedbCollection } from "../../../src/lib/storage/nedb/NedbCollection"; +import { NedbCollection } from "./NedbCollection"; -describe("NedbCollection", function () { +describe("storage/nedb/NedbCollection", function () { describe("insert", function () { it("should insert one entry", function () { const nedbOptions = { diff --git a/server/test/storage/nedb/NedbCollectionFactory.test.ts b/server/src/lib/storage/nedb/NedbCollectionFactory.spec.ts similarity index 69% rename from server/test/storage/nedb/NedbCollectionFactory.test.ts rename to server/src/lib/storage/nedb/NedbCollectionFactory.spec.ts index d63390914..da90c661f 100644 --- a/server/test/storage/nedb/NedbCollectionFactory.test.ts +++ b/server/src/lib/storage/nedb/NedbCollectionFactory.spec.ts @@ -1,9 +1,9 @@ import Sinon = require("sinon"); import Assert = require("assert"); -import { NedbCollectionFactory } from "../../../src/lib/storage/nedb/NedbCollectionFactory"; +import { NedbCollectionFactory } from "./NedbCollectionFactory"; -describe("NedbCollectionFactory", function() { +describe("storage/nedb/NedbCollectionFactory", function() { it("should create a nedb collection", function() { const nedbOptions = { inMemoryOnly: true diff --git a/server/test/mocks/express.ts b/server/src/lib/stubs/express.spec.ts similarity index 100% rename from server/test/mocks/express.ts rename to server/src/lib/stubs/express.spec.ts diff --git a/server/test/mocks/ldapjs.ts b/server/src/lib/stubs/ldapjs.spec.ts similarity index 100% rename from server/test/mocks/ldapjs.ts rename to server/src/lib/stubs/ldapjs.spec.ts diff --git a/server/test/mocks/speakeasy.ts b/server/src/lib/stubs/speakeasy.spec.ts similarity index 100% rename from server/test/mocks/speakeasy.ts rename to server/src/lib/stubs/speakeasy.spec.ts diff --git a/server/test/mocks/u2f.ts b/server/src/lib/stubs/u2f.spec.ts similarity index 100% rename from server/test/mocks/u2f.ts rename to server/src/lib/stubs/u2f.spec.ts diff --git a/server/test/utils/DomainExtractor.test.ts b/server/src/lib/utils/DomainExtractor.spec.ts similarity index 85% rename from server/test/utils/DomainExtractor.test.ts rename to server/src/lib/utils/DomainExtractor.spec.ts index 80c971d2b..c5910d886 100644 --- a/server/test/utils/DomainExtractor.test.ts +++ b/server/src/lib/utils/DomainExtractor.spec.ts @@ -1,7 +1,7 @@ -import { DomainExtractor } from "../../src/lib/utils/DomainExtractor"; +import { DomainExtractor } from "./DomainExtractor"; import Assert = require("assert"); -describe("test DomainExtractor", function () { +describe("utils/DomainExtractor", function () { describe("test fromUrl", function () { it("should return domain from https url", function () { const domain = DomainExtractor.fromUrl("https://www.example.com/test/abc"); diff --git a/server/test/utils/HashGenerator.test.ts b/server/src/lib/utils/HashGenerator.spec.ts similarity index 86% rename from server/test/utils/HashGenerator.test.ts rename to server/src/lib/utils/HashGenerator.spec.ts index e1637c5fc..0a94e3292 100644 --- a/server/test/utils/HashGenerator.test.ts +++ b/server/src/lib/utils/HashGenerator.spec.ts @@ -1,7 +1,7 @@ import Assert = require("assert"); -import { HashGenerator } from "../../src/lib/utils/HashGenerator"; +import { HashGenerator } from "./HashGenerator"; -describe("test HashGenerator", function () { +describe("utils/HashGenerator", function () { it("should compute correct ssha512 (password)", function () { return HashGenerator.ssha512("password", "jgiCMRyGXzoqpxS3") .then(function (hash: string) { diff --git a/server/src/lib/web_server/Configurator.ts b/server/src/lib/web_server/Configurator.ts index 5c3034d82..6e404874a 100644 --- a/server/src/lib/web_server/Configurator.ts +++ b/server/src/lib/web_server/Configurator.ts @@ -1,4 +1,4 @@ -import { AppConfiguration } from "../configuration/Configuration"; +import { Configuration } from "../configuration/schema/Configuration"; import { GlobalDependencies } from "../../../types/Dependencies"; import { SessionConfigurationBuilder } from "../configuration/SessionConfigurationBuilder"; @@ -20,7 +20,7 @@ const VIEW_ENGINE = "view engine"; const PUG = "pug"; export class Configurator { - static configure(config: AppConfiguration, + static configure(config: Configuration, app: Express.Application, vars: ServerVariables, deps: GlobalDependencies): void { diff --git a/server/src/lib/web_server/middlewares/RequireTwoFactorEnabled.ts b/server/src/lib/web_server/middlewares/RequireTwoFactorEnabled.ts index c97b57d99..6f8db4058 100644 --- a/server/src/lib/web_server/middlewares/RequireTwoFactorEnabled.ts +++ b/server/src/lib/web_server/middlewares/RequireTwoFactorEnabled.ts @@ -4,7 +4,7 @@ import ErrorReplies = require("../../ErrorReplies"); import { IRequestLogger } from "../../logging/IRequestLogger"; import { MethodCalculator } from "../../authentication/MethodCalculator"; import { AuthenticationMethodsConfiguration } from - "../../configuration/Configuration"; + "../../configuration/schema/AuthenticationMethodsConfiguration"; export class RequireTwoFactorEnabled { static middleware(logger: IRequestLogger, diff --git a/server/test/configuration/LdapConfigurationAdaptation.test.ts b/server/test/configuration/LdapConfigurationAdaptation.test.ts deleted file mode 100644 index bfcc8fc00..000000000 --- a/server/test/configuration/LdapConfigurationAdaptation.test.ts +++ /dev/null @@ -1,100 +0,0 @@ -import * as Assert from "assert"; -import { UserConfiguration, LdapConfiguration } from "../../src/lib/configuration/Configuration"; -import { ConfigurationParser } from "../../src/lib/configuration/ConfigurationParser"; - -describe("test ldap configuration adaptation", function () { - function build_yaml_config(): UserConfiguration { - const yaml_config: UserConfiguration = { - port: 8080, - ldap: { - url: "http://ldap", - base_dn: "dc=example,dc=com", - additional_users_dn: "ou=users", - additional_groups_dn: "ou=groups", - user: "user", - password: "pass" - }, - session: { - domain: "example.com", - secret: "secret", - expiration: 40000 - }, - storage: { - local: { - path: "/mydirectory" - } - }, - regulation: { - max_retries: 3, - ban_time: 5 * 60, - find_time: 5 * 60, - }, - logs_level: "debug", - notifier: { - email: { - username: "user", - password: "password", - sender: "admin@example.com", - service: "email" - } - } - }; - return yaml_config; - } - - it("should adapt correctly while user only specify mandatory fields", function () { - const userConfig = build_yaml_config(); - userConfig.ldap = { - url: "http://ldap", - base_dn: "dc=example,dc=com", - user: "admin", - password: "password" - }; - - const config = ConfigurationParser.parse(userConfig); - const expectedConfig: LdapConfiguration = { - url: "http://ldap", - users_dn: "dc=example,dc=com", - users_filter: "cn={0}", - groups_dn: "dc=example,dc=com", - groups_filter: "member={dn}", - group_name_attribute: "cn", - mail_attribute: "mail", - user: "admin", - password: "password" - }; - - Assert.deepEqual(config.ldap, expectedConfig); - }); - - it("should adapt correctly while user specify every fields", function () { - const userConfig = build_yaml_config(); - userConfig.ldap = { - url: "http://ldap-server", - base_dn: "dc=example,dc=com", - additional_users_dn: "ou=users", - users_filter: "uid={0}", - additional_groups_dn: "ou=groups", - groups_filter: "uniqueMember={0}", - mail_attribute: "email", - group_name_attribute: "groupName", - user: "admin2", - password: "password2" - }; - - const config = ConfigurationParser.parse(userConfig); - const expectedConfig: LdapConfiguration = { - url: "http://ldap-server", - users_dn: "ou=users,dc=example,dc=com", - users_filter: "uid={0}", - groups_dn: "ou=groups,dc=example,dc=com", - groups_filter: "uniqueMember={0}", - mail_attribute: "email", - group_name_attribute: "groupName", - user: "admin2", - password: "password2" - }; - - Assert.deepEqual(config.ldap, expectedConfig); - }); -}); diff --git a/server/test/configuration/Validator.test.ts b/server/test/configuration/Validator.test.ts deleted file mode 100644 index e3cd48da7..000000000 --- a/server/test/configuration/Validator.test.ts +++ /dev/null @@ -1,187 +0,0 @@ -import { Validator } from "../../src/lib/configuration/Validator"; -import Assert = require("assert"); - -describe("test validator", function () { - it("should validate wrong user configurations", function () { - // Some examples - Assert.deepStrictEqual(Validator.isValid({}), [ - "data should have required property 'ldap'", - "data should have required property 'notifier'", - "data should have required property 'regulation'", - "data should have required property 'session'", - "data should have required property 'storage'" - ]); - - Assert.deepStrictEqual(Validator.isValid({ - ldap: {}, - notifier: {}, - regulation: {}, - session: {}, - storage: {} - }), [ - "data.ldap should have required property 'base_dn'", - "data.ldap should have required property 'password'", - "data.ldap should have required property 'url'", - "data.ldap should have required property 'user'", - "data.regulation should have required property 'ban_time'", - "data.regulation should have required property 'find_time'", - "data.regulation should have required property 'max_retries'", - "data.session should have required property 'domain'", - "data.session should have required property 'secret'", - "Storage must be either 'local' or 'mongo'", - "A notifier needs to be declared when server is used with two-factor" - ]); - - Assert.deepStrictEqual(Validator.isValid({ - ldap: { - base_dn: "dc=example,dc=com", - password: "password", - url: "ldap://ldap", - user: "user" - }, - notifier: { - abcd: [] - }, - regulation: { - ban_time: 120, - find_time: 30, - max_retries: 3 - }, - session: { - secret: "unsecure_secret", - domain: "mydomain" - }, - storage: { - abc: {} - } - }), [ - "data.storage has unknown key 'abc'", - "Notifier must be either 'filesystem', 'email' or 'smtp'" - ]); - }); - - it("should validate correct user configurations", function () { - Assert.deepStrictEqual(Validator.isValid({ - ldap: { - base_dn: "dc=example,dc=com", - password: "password", - url: "ldap://ldap", - user: "user" - }, - notifier: { - email: { - username: "user@gmail.com", - password: "pass", - sender: "admin@example.com", - service: "gmail" - } - }, - regulation: { - ban_time: 120, - find_time: 30, - max_retries: 3 - }, - session: { - secret: "unsecure_secret", - domain: "mydomain" - }, - storage: { - local: { - path: "/var/lib/authelia" - } - } - }), []); - }); - - it("should return false when notifier is not defined while there is at least \ -one second factor enabled sub-domain", function () { - const options1 = { - ldap: { - base_dn: "dc=example,dc=com", - password: "password", - url: "ldap://ldap", - user: "user" - }, - authentication_methods: { - default_method: "two_factor" - }, - notifier: {}, - regulation: { - ban_time: 120, - find_time: 30, - max_retries: 3 - }, - session: { - secret: "unsecure_secret", - domain: "mydomain" - }, - storage: { - local: { - path: "/var/lib/authelia" - } - } - }; - const options2 = { - ldap: { - base_dn: "dc=example,dc=com", - password: "password", - url: "ldap://ldap", - user: "user" - }, - authentication_methods: { - default_method: "two_factor" - }, - notifier: { - email: { - username: "user@gmail.com", - password: "pass", - sender: "admin@example.com", - service: "gmail" - } - }, - regulation: { - ban_time: 120, - find_time: 30, - max_retries: 3 - }, - session: { - secret: "unsecure_secret", - domain: "mydomain" - }, - storage: { - local: { - path: "/var/lib/authelia" - } - } - }; - const options3 = { - ldap: { - base_dn: "dc=example,dc=com", - password: "password", - url: "ldap://ldap", - user: "user" - }, - authentication_methods: { - default_method: "single_factor" - }, - notifier: {}, - regulation: { - ban_time: 120, - find_time: 30, - max_retries: 3 - }, - session: { - secret: "unsecure_secret", - domain: "mydomain" - }, - storage: { - local: { - path: "/var/lib/authelia" - } - } - }; - Assert.deepStrictEqual(Validator.isValid(options1), ["A notifier needs to be declared when server is used with two-factor"]); - Assert.deepStrictEqual(Validator.isValid(options2), []); - Assert.deepStrictEqual(Validator.isValid(options3), []); - }); -}); \ No newline at end of file diff --git a/server/test/configuration/adapters/ACLAdapter.test.ts b/server/test/configuration/adapters/ACLAdapter.test.ts deleted file mode 100644 index 01bb32585..000000000 --- a/server/test/configuration/adapters/ACLAdapter.test.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { ACLAdapter } from "../../../src/lib/configuration/adapters/ACLAdapter"; -import Assert = require("assert"); - -describe("test ACL configuration adapter", function () { - - describe("bad default_policy", function () { - it("should adapt a configuration missing default_policy", function () { - const userConfiguration: any = { - any: [], - groups: {}, - users: {} - }; - - const appConfiguration = ACLAdapter.adapt(userConfiguration); - Assert.deepStrictEqual(appConfiguration, { - default_policy: "deny", - any: [], - groups: {}, - users: {} - }); - }); - - it("should adapt a configuration with bad default_policy value", function () { - const userConfiguration: any = { - default_policy: "anything", // it should be 'allow' or 'deny' - any: [], - groups: {}, - users: {} - }; - - const appConfiguration = ACLAdapter.adapt(userConfiguration); - Assert.deepStrictEqual(appConfiguration, { - default_policy: "deny", - any: [], - groups: {}, - users: {} - }); - }); - - it("should adapt a configuration with bad default_policy type", function () { - const userConfiguration: any = { - default_policy: {}, // it should be 'allow' or 'deny' - any: [], - groups: {}, - users: {} - }; - - const appConfiguration = ACLAdapter.adapt(userConfiguration); - Assert.deepStrictEqual(appConfiguration, { - default_policy: "deny", - any: [], - groups: {}, - users: {} - }); - }); - }); - - describe("bad any", function () { - it("should adapt a configuration missing any key", function () { - const userConfiguration: any = { - default_policy: "deny", - groups: {}, - users: {} - }; - - const appConfiguration = ACLAdapter.adapt(userConfiguration); - Assert.deepStrictEqual(appConfiguration, { - default_policy: "deny", - any: [], - groups: {}, - users: {} - }); - }); - - it("should adapt a configuration with any not being an array", function () { - const userConfiguration: any = { - default_policy: "deny", - any: "abc", - groups: {}, - users: {} - }; - - const appConfiguration = ACLAdapter.adapt(userConfiguration); - Assert.deepStrictEqual(appConfiguration, { - default_policy: "deny", - any: [], - groups: {}, - users: {} - }); - }); - }); - - describe("bad groups", function () { - it("should adapt a configuration missing groups key", function () { - const userConfiguration: any = { - default_policy: "deny", - any: [], - users: {} - }; - - const appConfiguration = ACLAdapter.adapt(userConfiguration); - Assert.deepStrictEqual(appConfiguration, { - default_policy: "deny", - any: [], - groups: {}, - users: {} - }); - }); - - it("should adapt configuration with groups being of wrong type", function () { - const userConfiguration: any = { - default_policy: "deny", - any: [], - groups: [], - users: {} - }; - - const appConfiguration = ACLAdapter.adapt(userConfiguration); - Assert.deepStrictEqual(appConfiguration, { - default_policy: "deny", - any: [], - groups: {}, - users: {} - }); - }); - }); - - describe("bad users", function () { - it("should adapt a configuration missing users key", function () { - const userConfiguration: any = { - default_policy: "deny", - any: [], - groups: {} - }; - - const appConfiguration = ACLAdapter.adapt(userConfiguration); - Assert.deepStrictEqual(appConfiguration, { - default_policy: "deny", - any: [], - groups: {}, - users: {} - }); - }); - - it("should adapt a configuration with users being of wrong type", function () { - const userConfiguration: any = { - default_policy: "deny", - any: [], - groups: {}, - users: [] - }; - - const appConfiguration = ACLAdapter.adapt(userConfiguration); - Assert.deepStrictEqual(appConfiguration, { - default_policy: "deny", - any: [], - groups: {}, - users: {} - }); - }); - }); -}); \ No newline at end of file diff --git a/server/test/configuration/adapters/AuthenticationMethodsAdapter.test.ts b/server/test/configuration/adapters/AuthenticationMethodsAdapter.test.ts deleted file mode 100644 index 3e88e5721..000000000 --- a/server/test/configuration/adapters/AuthenticationMethodsAdapter.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { AuthenticationMethodsAdapter } from "../../../src/lib/configuration/adapters/AuthenticationMethodsAdapter"; -import Assert = require("assert"); - -describe("test authentication methods configuration adapter", function () { - describe("no authentication methods defined", function () { - it("should adapt a configuration when no authentication methods config is defined", function () { - const userConfiguration: any = undefined; - - const appConfiguration = AuthenticationMethodsAdapter.adapt(userConfiguration); - Assert.deepStrictEqual(appConfiguration, { - default_method: "two_factor", - per_subdomain_methods: {} - }); - }); - }); - - describe("partial authentication methods config", function() { - it("should adapt a configuration when default_method is not defined", function () { - const userConfiguration: any = { - per_subdomain_methods: { - "example.com": "single_factor" - } - }; - - const appConfiguration = AuthenticationMethodsAdapter.adapt(userConfiguration); - Assert.deepStrictEqual(appConfiguration, { - default_method: "two_factor", - per_subdomain_methods: { - "example.com": "single_factor" - } - }); - }); - - it("should adapt a configuration when per_subdomain_methods is not defined", function () { - const userConfiguration: any = { - default_method: "single_factor" - }; - - const appConfiguration = AuthenticationMethodsAdapter.adapt(userConfiguration); - Assert.deepStrictEqual(appConfiguration, { - default_method: "single_factor", - per_subdomain_methods: {} - }); - }); - - it("should adapt a configuration when per_subdomain_methods has wrong type", function () { - const userConfiguration: any = { - default_method: "single_factor", - per_subdomain_methods: [] - }; - - const appConfiguration = AuthenticationMethodsAdapter.adapt(userConfiguration); - Assert.deepStrictEqual(appConfiguration, { - default_method: "single_factor", - per_subdomain_methods: {} - }); - }); - }); -}); diff --git a/server/test/mocks/AuthenticationRegulator.ts b/server/test/mocks/AuthenticationRegulator.ts deleted file mode 100644 index 2d789d94e..000000000 --- a/server/test/mocks/AuthenticationRegulator.ts +++ /dev/null @@ -1,15 +0,0 @@ - -import sinon = require("sinon"); - - -export interface AuthenticationRegulatorMock { - mark: sinon.SinonStub; - regulate: sinon.SinonStub; -} - -export function AuthenticationRegulatorMock() { - return { - mark: sinon.stub(), - regulate: sinon.stub() - }; -} diff --git a/server/test/mocks/IdentityValidator.ts b/server/test/mocks/IdentityValidator.ts deleted file mode 100644 index 3fbe44dc3..000000000 --- a/server/test/mocks/IdentityValidator.ts +++ /dev/null @@ -1,39 +0,0 @@ - -import sinon = require("sinon"); -import { IdentityValidable } from "../../src/lib/IdentityCheckMiddleware"; -import express = require("express"); -import BluebirdPromise = require("bluebird"); -import { Identity } from "../../types/Identity"; - - -export interface IdentityValidableMock { - challenge: sinon.SinonStub; - preValidationInit: sinon.SinonStub; - preValidationResponse: sinon.SinonStub | sinon.SinonSpy; - postValidationInit: sinon.SinonStub; - postValidationResponse: sinon.SinonStub | sinon.SinonSpy; - mailSubject: sinon.SinonStub; -} - -export function IdentityValidableMock() { - return { - challenge: sinon.stub(), - preValidationInit: sinon.stub(), - preValidationResponse: sinon.stub(), - postValidationInit: sinon.stub(), - postValidationResponse: sinon.stub(), - mailSubject: sinon.stub() - }; -} - -export interface IdentityValidatorMock { - consume_token: sinon.SinonStub; - issue_token: sinon.SinonStub; -} - -export function IdentityValidatorMock() { - return { - consume_token: sinon.stub(), - issue_token: sinon.stub() - }; -} \ No newline at end of file diff --git a/server/test/mocks/Notifier.ts b/server/test/mocks/Notifier.ts deleted file mode 100644 index 951604088..000000000 --- a/server/test/mocks/Notifier.ts +++ /dev/null @@ -1,12 +0,0 @@ - -import sinon = require("sinon"); - -export interface NotifierMock { - notify: sinon.SinonStub; -} - -export function NotifierMock(): NotifierMock { - return { - notify: sinon.stub() - }; -} diff --git a/server/test/mocks/RegulatorStub.ts b/server/test/mocks/RegulatorStub.ts deleted file mode 100644 index 203c0e23a..000000000 --- a/server/test/mocks/RegulatorStub.ts +++ /dev/null @@ -1,21 +0,0 @@ -import Sinon = require("sinon"); -import BluebirdPromise = require("bluebird"); -import { IRegulator } from "../../src/lib/regulation/IRegulator"; - -export class RegulatorStub implements IRegulator { - markStub: Sinon.SinonStub; - regulateStub: Sinon.SinonStub; - - constructor() { - this.markStub = Sinon.stub(); - this.regulateStub = Sinon.stub(); - } - - mark(userId: string, isAuthenticationSuccessful: boolean): BluebirdPromise { - return this.markStub(userId, isAuthenticationSuccessful); - } - - regulate(userId: string): BluebirdPromise { - return this.regulateStub(userId); - } -} \ No newline at end of file diff --git a/server/test/mocks/TOTPValidator.ts b/server/test/mocks/TOTPValidator.ts deleted file mode 100644 index 56434c79b..000000000 --- a/server/test/mocks/TOTPValidator.ts +++ /dev/null @@ -1,12 +0,0 @@ - -import sinon = require("sinon"); - -export interface TOTPValidatorMock { - validate: sinon.SinonStub; -} - -export function TOTPValidatorMock(): TOTPValidatorMock { - return { - validate: sinon.stub() - }; -} diff --git a/server/tsconfig.json b/server/tsconfig.json index 0bb4d62ff..ebe98c5ed 100644 --- a/server/tsconfig.json +++ b/server/tsconfig.json @@ -15,10 +15,7 @@ ] } }, - "include": [ - "src/**/*" - ], "exclude": [ - "test/**/*" + "src/**/*.spec.ts" ] } diff --git a/test/features/step_definitions/authentication.ts b/test/features/step_definitions/authentication.ts index 4fad123a9..7c12e4da0 100644 --- a/test/features/step_definitions/authentication.ts +++ b/test/features/step_definitions/authentication.ts @@ -64,7 +64,7 @@ When("I visit {string} and get redirected {string}", const that = this; return this.driver.get(url) .then(function () { - return that.driver.wait(seleniumWebdriver.until.urlIs(redirectUrl), 6000); + return that.driver.wait(seleniumWebdriver.until.urlIs(redirectUrl), 5000); }); }); @@ -96,4 +96,4 @@ Then("the following endpoints reply with:", function (dataTable: TableDefinition promises.push(endpointReplyWith(this, url, method, code)); } return BluebirdPromise.all(promises); -}); \ No newline at end of file +}); diff --git a/test/features/support/world.ts b/test/features/support/world.ts index b848f643d..1a27bd250 100644 --- a/test/features/support/world.ts +++ b/test/features/support/world.ts @@ -34,7 +34,7 @@ function CustomWorld() { this.getErrorPage = function (code: number) { const that = this; - return this.driver.wait(seleniumWebdriver.until.elementLocated(seleniumWebdriver.By.tagName("h1")), 2000) + return this.driver.wait(seleniumWebdriver.until.elementLocated(seleniumWebdriver.By.tagName("h1")), 5000) .then(function () { return that.driver .findElement(seleniumWebdriver.By.tagName("h1")).getText(); @@ -51,7 +51,7 @@ function CustomWorld() { this.clickOnButton = function (buttonText: string) { const that = this; - return this.driver.wait(seleniumWebdriver.until.elementLocated(seleniumWebdriver.By.tagName("button")), 2000) + return this.driver.wait(seleniumWebdriver.until.elementLocated(seleniumWebdriver.By.tagName("button")), 5000) .then(function () { return that.driver .findElement(seleniumWebdriver.By.tagName("button")) @@ -73,7 +73,7 @@ function CustomWorld() { }; this.loginWithUserPassword = function (username: string, password: string) { - return that.driver.wait(seleniumWebdriver.until.elementLocated(seleniumWebdriver.By.id("username")), 4000) + return that.driver.wait(seleniumWebdriver.until.elementLocated(seleniumWebdriver.By.id("username")), 5000) .then(function () { return that.driver.findElement(seleniumWebdriver.By.id("username")) .sendKeys(username); @@ -114,7 +114,7 @@ function CustomWorld() { }; this.registerTotpSecret = function (totpSecretHandle: string) { - return that.driver.wait(seleniumWebdriver.until.elementLocated(seleniumWebdriver.By.className("register-totp")), 4000) + return that.driver.wait(seleniumWebdriver.until.elementLocated(seleniumWebdriver.By.className("register-totp")), 5000) .then(function () { return that.driver.findElement(seleniumWebdriver.By.className("register-totp")).click(); }) From 73be5bfc68c04022b5f2bf6e68da03a201eaf363 Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Sun, 5 Aug 2018 16:02:56 +0200 Subject: [PATCH 2/5] Fix missing default value in configuration --- server/src/lib/configuration/ConfigurationParser.ts | 4 ++-- server/src/lib/configuration/schema/NotifierConfiguration.ts | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/server/src/lib/configuration/ConfigurationParser.ts b/server/src/lib/configuration/ConfigurationParser.ts index a67632c3b..d92d163c4 100644 --- a/server/src/lib/configuration/ConfigurationParser.ts +++ b/server/src/lib/configuration/ConfigurationParser.ts @@ -24,14 +24,14 @@ export class ConfigurationParser { const validationErrors = this.parseTypes(configuration); if (validationErrors.length > 0) { validationErrors.forEach((e: string) => { console.log(e); }); - throw new Error("Malformed configuration. Please double-check your configuration file."); + throw new Error("Malformed configuration (schema). Please double-check your configuration file."); } const [newConfiguration, completionErrors] = complete(configuration); if (completionErrors.length > 0) { completionErrors.forEach((e: string) => { console.log(e); }); - throw new Error("Malformed configuration. Please double-check your configuration file."); + throw new Error("Malformed configuration (validator). Please double-check your configuration file."); } return newConfiguration; } diff --git a/server/src/lib/configuration/schema/NotifierConfiguration.ts b/server/src/lib/configuration/schema/NotifierConfiguration.ts index 497220ef5..a4e1b0ed0 100644 --- a/server/src/lib/configuration/schema/NotifierConfiguration.ts +++ b/server/src/lib/configuration/schema/NotifierConfiguration.ts @@ -28,6 +28,9 @@ export interface NotifierConfiguration { export function complete(configuration: NotifierConfiguration): [NotifierConfiguration, string] { const newConfiguration: NotifierConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {}; + if (Object.keys(newConfiguration).length == 0) + newConfiguration.filesystem = { filename: '/tmp/authelia-notification.txt' }; + const ERROR = "Notifier must have one of the following keys: 'filesystem', 'email' or 'smtp'"; if (Object.keys(newConfiguration).length != 1) From 35fbea355fd7e82ad1d960f4bbd5cc507e32983d Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Sun, 5 Aug 2018 16:03:35 +0200 Subject: [PATCH 3/5] Fix logging after configuration refactoring --- server/src/lib/Server.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/src/lib/Server.ts b/server/src/lib/Server.ts index c8e969e7a..6bd1e2989 100644 --- a/server/src/lib/Server.ts +++ b/server/src/lib/Server.ts @@ -57,6 +57,7 @@ export default class Server { private startServer(app: Express.Application, port: number) { const that = this; + that.globalLogger.info("Starting Authelia..."); return new BluebirdPromise((resolve, reject) => { this.httpServer = app.listen(port, function (err: string) { that.globalLogger.info("Listening on port %d...", port); @@ -73,8 +74,8 @@ export default class Server { const appConfiguration = ConfigurationParser.parse(configuration); // by default the level of logs is info - deps.winston.level = configuration.logs_level; - this.displayConfigurations(configuration); + deps.winston.level = appConfiguration.logs_level; + this.displayConfigurations(appConfiguration); return this.setup(appConfiguration, app, deps) .then(function () { From 21653bc7e35e7ec9d2d41cefedc63f879796792f Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Tue, 7 Aug 2018 22:55:36 +0200 Subject: [PATCH 4/5] Remove old unmaintained documentation Will be replaced by the wiki documentation soon. --- doc/api_data.js | 996 ------------------- doc/api_data.json | 996 ------------------- doc/api_project.js | 15 - doc/api_project.json | 15 - doc/css/style.css | 569 ----------- doc/fonts/glyphicons-halflings-regular.eot | Bin 20127 -> 0 bytes doc/fonts/glyphicons-halflings-regular.svg | 288 ------ doc/fonts/glyphicons-halflings-regular.ttf | Bin 45404 -> 0 bytes doc/fonts/glyphicons-halflings-regular.woff | Bin 23424 -> 0 bytes doc/fonts/glyphicons-halflings-regular.woff2 | Bin 18028 -> 0 bytes doc/img/favicon.ico | Bin 894 -> 0 bytes doc/index.html | 669 ------------- doc/locales/ca.js | 25 - doc/locales/de.js | 25 - doc/locales/es.js | 25 - doc/locales/fr.js | 25 - doc/locales/it.js | 25 - doc/locales/locale.js | 50 - doc/locales/nl.js | 25 - doc/locales/pl.js | 25 - doc/locales/pt_br.js | 25 - doc/locales/ro.js | 25 - doc/locales/ru.js | 25 - doc/locales/tr.js | 25 - doc/locales/vi.js | 25 - doc/locales/zh.js | 25 - doc/locales/zh_cn.js | 25 - doc/main.js | 827 --------------- doc/utils/handlebars_helper.js | 357 ------- doc/utils/send_sample_request.js | 184 ---- doc/vendor/bootstrap.min.css | 6 - doc/vendor/bootstrap.min.js | 7 - doc/vendor/diff_match_patch.min.js | 49 - doc/vendor/handlebars.min.js | 29 - doc/vendor/jquery.min.js | 4 - doc/vendor/list.min.js | 2 - doc/vendor/lodash.custom.min.js | 41 - doc/vendor/path-to-regexp/LICENSE | 21 - doc/vendor/path-to-regexp/index.js | 204 ---- doc/vendor/polyfill.js | 96 -- doc/vendor/prettify.css | 51 - doc/vendor/prettify/lang-Splus.js | 18 - doc/vendor/prettify/lang-aea.js | 18 - doc/vendor/prettify/lang-agc.js | 18 - doc/vendor/prettify/lang-apollo.js | 18 - doc/vendor/prettify/lang-basic.js | 18 - doc/vendor/prettify/lang-cbm.js | 18 - doc/vendor/prettify/lang-cl.js | 18 - doc/vendor/prettify/lang-clj.js | 17 - doc/vendor/prettify/lang-css.js | 18 - doc/vendor/prettify/lang-dart.js | 19 - doc/vendor/prettify/lang-el.js | 18 - doc/vendor/prettify/lang-erl.js | 18 - doc/vendor/prettify/lang-erlang.js | 18 - doc/vendor/prettify/lang-fs.js | 18 - doc/vendor/prettify/lang-go.js | 17 - doc/vendor/prettify/lang-hs.js | 18 - doc/vendor/prettify/lang-lasso.js | 19 - doc/vendor/prettify/lang-lassoscript.js | 19 - doc/vendor/prettify/lang-latex.js | 17 - doc/vendor/prettify/lang-lgt.js | 18 - doc/vendor/prettify/lang-lisp.js | 18 - doc/vendor/prettify/lang-ll.js | 17 - doc/vendor/prettify/lang-llvm.js | 17 - doc/vendor/prettify/lang-logtalk.js | 18 - doc/vendor/prettify/lang-ls.js | 19 - doc/vendor/prettify/lang-lsp.js | 18 - doc/vendor/prettify/lang-lua.js | 18 - doc/vendor/prettify/lang-matlab.js | 29 - doc/vendor/prettify/lang-ml.js | 18 - doc/vendor/prettify/lang-mumps.js | 18 - doc/vendor/prettify/lang-n.js | 19 - doc/vendor/prettify/lang-nemerle.js | 19 - doc/vendor/prettify/lang-pascal.js | 18 - doc/vendor/prettify/lang-proto.js | 17 - doc/vendor/prettify/lang-r.js | 18 - doc/vendor/prettify/lang-rd.js | 17 - doc/vendor/prettify/lang-rkt.js | 18 - doc/vendor/prettify/lang-rust.js | 20 - doc/vendor/prettify/lang-s.js | 18 - doc/vendor/prettify/lang-scala.js | 18 - doc/vendor/prettify/lang-scm.js | 18 - doc/vendor/prettify/lang-sql.js | 18 - doc/vendor/prettify/lang-ss.js | 18 - doc/vendor/prettify/lang-swift.js | 16 - doc/vendor/prettify/lang-tcl.js | 18 - doc/vendor/prettify/lang-tex.js | 17 - doc/vendor/prettify/lang-vb.js | 19 - doc/vendor/prettify/lang-vbs.js | 19 - doc/vendor/prettify/lang-vhd.js | 19 - doc/vendor/prettify/lang-vhdl.js | 19 - doc/vendor/prettify/lang-wiki.js | 18 - doc/vendor/prettify/lang-xq.js | 19 - doc/vendor/prettify/lang-xquery.js | 19 - doc/vendor/prettify/lang-yaml.js | 18 - doc/vendor/prettify/lang-yml.js | 18 - doc/vendor/prettify/prettify.css | 1 - doc/vendor/prettify/prettify.js | 46 - doc/vendor/prettify/run_prettify.js | 63 -- doc/vendor/require.min.js | 37 - doc/vendor/semver.min.js | 1 - doc/vendor/webfontloader.js | 17 - 102 files changed, 6996 deletions(-) delete mode 100644 doc/api_data.js delete mode 100644 doc/api_data.json delete mode 100644 doc/api_project.js delete mode 100644 doc/api_project.json delete mode 100644 doc/css/style.css delete mode 100644 doc/fonts/glyphicons-halflings-regular.eot delete mode 100644 doc/fonts/glyphicons-halflings-regular.svg delete mode 100644 doc/fonts/glyphicons-halflings-regular.ttf delete mode 100644 doc/fonts/glyphicons-halflings-regular.woff delete mode 100644 doc/fonts/glyphicons-halflings-regular.woff2 delete mode 100644 doc/img/favicon.ico delete mode 100644 doc/index.html delete mode 100644 doc/locales/ca.js delete mode 100644 doc/locales/de.js delete mode 100644 doc/locales/es.js delete mode 100644 doc/locales/fr.js delete mode 100644 doc/locales/it.js delete mode 100644 doc/locales/locale.js delete mode 100644 doc/locales/nl.js delete mode 100644 doc/locales/pl.js delete mode 100644 doc/locales/pt_br.js delete mode 100644 doc/locales/ro.js delete mode 100644 doc/locales/ru.js delete mode 100644 doc/locales/tr.js delete mode 100644 doc/locales/vi.js delete mode 100644 doc/locales/zh.js delete mode 100644 doc/locales/zh_cn.js delete mode 100644 doc/main.js delete mode 100644 doc/utils/handlebars_helper.js delete mode 100755 doc/utils/send_sample_request.js delete mode 100644 doc/vendor/bootstrap.min.css delete mode 100644 doc/vendor/bootstrap.min.js delete mode 100644 doc/vendor/diff_match_patch.min.js delete mode 100644 doc/vendor/handlebars.min.js delete mode 100644 doc/vendor/jquery.min.js delete mode 100644 doc/vendor/list.min.js delete mode 100644 doc/vendor/lodash.custom.min.js delete mode 100644 doc/vendor/path-to-regexp/LICENSE delete mode 100644 doc/vendor/path-to-regexp/index.js delete mode 100644 doc/vendor/polyfill.js delete mode 100644 doc/vendor/prettify.css delete mode 100644 doc/vendor/prettify/lang-Splus.js delete mode 100644 doc/vendor/prettify/lang-aea.js delete mode 100644 doc/vendor/prettify/lang-agc.js delete mode 100644 doc/vendor/prettify/lang-apollo.js delete mode 100644 doc/vendor/prettify/lang-basic.js delete mode 100644 doc/vendor/prettify/lang-cbm.js delete mode 100644 doc/vendor/prettify/lang-cl.js delete mode 100644 doc/vendor/prettify/lang-clj.js delete mode 100644 doc/vendor/prettify/lang-css.js delete mode 100644 doc/vendor/prettify/lang-dart.js delete mode 100644 doc/vendor/prettify/lang-el.js delete mode 100644 doc/vendor/prettify/lang-erl.js delete mode 100644 doc/vendor/prettify/lang-erlang.js delete mode 100644 doc/vendor/prettify/lang-fs.js delete mode 100644 doc/vendor/prettify/lang-go.js delete mode 100644 doc/vendor/prettify/lang-hs.js delete mode 100644 doc/vendor/prettify/lang-lasso.js delete mode 100644 doc/vendor/prettify/lang-lassoscript.js delete mode 100644 doc/vendor/prettify/lang-latex.js delete mode 100644 doc/vendor/prettify/lang-lgt.js delete mode 100644 doc/vendor/prettify/lang-lisp.js delete mode 100644 doc/vendor/prettify/lang-ll.js delete mode 100644 doc/vendor/prettify/lang-llvm.js delete mode 100644 doc/vendor/prettify/lang-logtalk.js delete mode 100644 doc/vendor/prettify/lang-ls.js delete mode 100644 doc/vendor/prettify/lang-lsp.js delete mode 100644 doc/vendor/prettify/lang-lua.js delete mode 100644 doc/vendor/prettify/lang-matlab.js delete mode 100644 doc/vendor/prettify/lang-ml.js delete mode 100644 doc/vendor/prettify/lang-mumps.js delete mode 100644 doc/vendor/prettify/lang-n.js delete mode 100644 doc/vendor/prettify/lang-nemerle.js delete mode 100644 doc/vendor/prettify/lang-pascal.js delete mode 100644 doc/vendor/prettify/lang-proto.js delete mode 100644 doc/vendor/prettify/lang-r.js delete mode 100644 doc/vendor/prettify/lang-rd.js delete mode 100644 doc/vendor/prettify/lang-rkt.js delete mode 100644 doc/vendor/prettify/lang-rust.js delete mode 100644 doc/vendor/prettify/lang-s.js delete mode 100644 doc/vendor/prettify/lang-scala.js delete mode 100644 doc/vendor/prettify/lang-scm.js delete mode 100644 doc/vendor/prettify/lang-sql.js delete mode 100644 doc/vendor/prettify/lang-ss.js delete mode 100644 doc/vendor/prettify/lang-swift.js delete mode 100644 doc/vendor/prettify/lang-tcl.js delete mode 100644 doc/vendor/prettify/lang-tex.js delete mode 100644 doc/vendor/prettify/lang-vb.js delete mode 100644 doc/vendor/prettify/lang-vbs.js delete mode 100644 doc/vendor/prettify/lang-vhd.js delete mode 100644 doc/vendor/prettify/lang-vhdl.js delete mode 100644 doc/vendor/prettify/lang-wiki.js delete mode 100644 doc/vendor/prettify/lang-xq.js delete mode 100644 doc/vendor/prettify/lang-xquery.js delete mode 100644 doc/vendor/prettify/lang-yaml.js delete mode 100644 doc/vendor/prettify/lang-yml.js delete mode 100644 doc/vendor/prettify/prettify.css delete mode 100644 doc/vendor/prettify/prettify.js delete mode 100644 doc/vendor/prettify/run_prettify.js delete mode 100644 doc/vendor/require.min.js delete mode 100644 doc/vendor/semver.min.js delete mode 100644 doc/vendor/webfontloader.js diff --git a/doc/api_data.js b/doc/api_data.js deleted file mode 100644 index 7aba8ada3..000000000 --- a/doc/api_data.js +++ /dev/null @@ -1,996 +0,0 @@ -define({ "api": [ - { - "type": "get", - "url": "/", - "title": "First factor page", - "name": "Login", - "group": "Authentication", - "version": "1.0.0", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "Content", - "description": "

The content of the first factor page.

" - } - ] - } - }, - "description": "

Serves the login page and create a create a cookie for the client.

", - "filename": "shared/api.ts", - "groupTitle": "Authentication" - }, - { - "type": "get", - "url": "/logout", - "title": "Serves logout page", - "name": "Logout", - "group": "Authentication", - "version": "1.0.0", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "redirect", - "description": "

Redirect to this URL when user is deauthenticated.

" - } - ] - } - }, - "success": { - "fields": { - "Success 302": [ - { - "group": "Success 302", - "optional": false, - "field": "redirect", - "description": "

Redirect to the URL.

" - } - ] - } - }, - "description": "

Log out the user and redirect to the URL.

", - "filename": "shared/api.ts", - "groupTitle": "Authentication" - }, - { - "type": "get", - "url": "/secondfactor", - "title": "Second factor page", - "name": "SecondFactor", - "group": "Authentication", - "version": "1.0.0", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "Content", - "description": "

The content of second factor page.

" - } - ] - } - }, - "description": "

Serves the second factor page

", - "filename": "shared/api.ts", - "groupTitle": "Authentication" - }, - { - "type": "post", - "url": "/1stfactor", - "title": "Bind user against LDAP", - "name": "ValidateFirstFactor", - "group": "Authentication", - "version": "1.0.0", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "username", - "description": "

User username.

" - }, - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "password", - "description": "

User password.

" - } - ] - } - }, - "success": { - "fields": { - "Success 204": [ - { - "group": "Success 204", - "optional": false, - "field": "status", - "description": "

1st factor is validated.

" - } - ] - } - }, - "error": { - "fields": { - "Error 401": [ - { - "group": "Error 401", - "type": "none", - "optional": false, - "field": "error", - "description": "

1st factor is not validated.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - }, - "description": "

Verify credentials against the LDAP.

", - "filename": "shared/api.ts", - "groupTitle": "Authentication", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - } - }, - { - "type": "post", - "url": "/reset-password/request", - "title": "Finish password reset request", - "name": "FinishPasswordResetRequest", - "group": "PasswordReset", - "version": "1.0.0", - "description": "

Start password reset request.

", - "filename": "shared/api.ts", - "groupTitle": "PasswordReset", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - }, - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "identity_token", - "description": "

The one-time identity validation token provided in the email.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "content", - "description": "

The content of the page.

" - } - ] - } - }, - "error": { - "fields": { - "Error 403": [ - { - "group": "Error 403", - "optional": false, - "field": "AccessDenied", - "description": "

Access is denied.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - } - }, - { - "type": "get", - "url": "/password-reset/request", - "title": "Request username", - "name": "ServePasswordResetPage", - "group": "PasswordReset", - "version": "1.0.0", - "description": "

Serve a page that requires the username.

", - "filename": "shared/api.ts", - "groupTitle": "PasswordReset", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - } - }, - { - "type": "post", - "url": "/api/password-reset", - "title": "Set new password", - "name": "SetNewLDAPPassword", - "group": "PasswordReset", - "version": "1.0.0", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "password", - "description": "

New password

" - } - ] - } - }, - "description": "

Set a new password for the user.

", - "filename": "shared/api.ts", - "groupTitle": "PasswordReset", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - } - }, - { - "type": "get", - "url": "/password-reset/identity/start", - "title": "Start password reset request", - "name": "StartPasswordResetRequest", - "group": "PasswordReset", - "version": "1.0.0", - "description": "

Start password reset request.

", - "filename": "shared/api.ts", - "groupTitle": "PasswordReset", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - }, - "success": { - "fields": { - "Success 204": [ - { - "group": "Success 204", - "optional": false, - "field": "status", - "description": "

Identity validation has been initiated.

" - } - ] - } - }, - "error": { - "fields": { - "Error 403": [ - { - "group": "Error 403", - "optional": false, - "field": "AccessDenied", - "description": "

Access is denied.

" - } - ], - "Error 400": [ - { - "group": "Error 400", - "optional": false, - "field": "InvalidIdentity", - "description": "

User identity is invalid.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - } - }, - { - "type": "get", - "url": "/secondfactor/totp/identity/finish", - "title": "Finish TOTP registration identity validation", - "name": "FinishTOTPRegistration", - "group": "TOTP", - "version": "1.0.0", - "description": "

Serves the TOTP registration page that displays the secret. The secret is a QRCode and a base32 secret.

", - "filename": "shared/api.ts", - "groupTitle": "TOTP", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - }, - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "identity_token", - "description": "

The one-time identity validation token provided in the email.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "content", - "description": "

The content of the page.

" - } - ] - } - }, - "error": { - "fields": { - "Error 403": [ - { - "group": "Error 403", - "optional": false, - "field": "AccessDenied", - "description": "

Access is denied.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - } - }, - { - "type": "get", - "url": "/secondfactor/totp/identity/start", - "title": "Start TOTP registration identity validation", - "name": "StartTOTPRegistration", - "group": "TOTP", - "version": "1.0.0", - "description": "

Initiates the identity validation

", - "filename": "shared/api.ts", - "groupTitle": "TOTP", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - }, - "success": { - "fields": { - "Success 204": [ - { - "group": "Success 204", - "optional": false, - "field": "status", - "description": "

Identity validation has been initiated.

" - } - ] - } - }, - "error": { - "fields": { - "Error 403": [ - { - "group": "Error 403", - "optional": false, - "field": "AccessDenied", - "description": "

Access is denied.

" - } - ], - "Error 400": [ - { - "group": "Error 400", - "optional": false, - "field": "InvalidIdentity", - "description": "

User identity is invalid.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - } - }, - { - "type": "post", - "url": "/api/totp", - "title": "Complete TOTP authentication", - "name": "ValidateTOTPSecondFactor", - "group": "TOTP", - "version": "1.0.0", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "token", - "description": "

TOTP token.

" - } - ] - } - }, - "success": { - "fields": { - "Success 302": [ - { - "group": "Success 302", - "optional": false, - "field": "Redirect", - "description": "

to the URL that has been stored during last call to /api/verify.

" - } - ] - } - }, - "error": { - "fields": { - "Error 401": [ - { - "group": "Error 401", - "type": "none", - "optional": false, - "field": "error", - "description": "

TOTP token is invalid.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - }, - "description": "

Verify TOTP token. The user is authenticated upon success.

", - "filename": "shared/api.ts", - "groupTitle": "TOTP", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - } - }, - { - "type": "post", - "url": "/api/u2f/sign", - "title": "Complete U2F authentication", - "name": "CompleteU2FAuthentication", - "group": "U2F", - "version": "1.0.0", - "success": { - "fields": { - "Success 302": [ - { - "group": "Success 302", - "optional": false, - "field": "Redirect", - "description": "

to the URL that has been stored during last call to /api/verify.

" - } - ] - } - }, - "error": { - "fields": { - "Error 403": [ - { - "group": "Error 403", - "type": "none", - "optional": false, - "field": "error", - "description": "

No authentication request has been provided.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - }, - "description": "

Complete authentication request of the U2F device.

", - "filename": "shared/api.ts", - "groupTitle": "U2F", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - } - }, - { - "type": "post", - "url": "/api/secondfactor/u2f/register", - "title": "Complete U2F registration", - "name": "FinishU2FRegistration", - "group": "U2F", - "version": "1.0.0", - "success": { - "fields": { - "Success 302": [ - { - "group": "Success 302", - "optional": false, - "field": "Redirect", - "description": "

to the URL that has been stored during last call to /api/verify.

" - } - ] - } - }, - "description": "

Complete U2F registration request.

", - "filename": "shared/api.ts", - "groupTitle": "U2F", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - }, - "error": { - "fields": { - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - } - }, - { - "type": "get", - "url": "/secondfactor/u2f/identity/start", - "title": "Start U2F registration identity validation", - "name": "RequestU2FRegistration", - "group": "U2F", - "version": "1.0.0", - "filename": "shared/api.ts", - "groupTitle": "U2F", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - }, - "success": { - "fields": { - "Success 204": [ - { - "group": "Success 204", - "optional": false, - "field": "status", - "description": "

Identity validation has been initiated.

" - } - ] - } - }, - "error": { - "fields": { - "Error 403": [ - { - "group": "Error 403", - "optional": false, - "field": "AccessDenied", - "description": "

Access is denied.

" - } - ], - "Error 400": [ - { - "group": "Error 400", - "optional": false, - "field": "InvalidIdentity", - "description": "

User identity is invalid.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - }, - "description": "

This request issue an identity validation token for the user bound to the session. It sends a challenge to the email address set in the user LDAP entry. The user must visit the sent URL to complete the validation and continue the registration process.

" - }, - { - "type": "get", - "url": "/secondfactor/u2f/identity/finish", - "title": "Finish U2F registration identity validation", - "name": "ServeU2FRegistrationPage", - "group": "U2F", - "version": "1.0.0", - "description": "

Serves the U2F registration page that asks the user to touch the token of the U2F device.

", - "filename": "shared/api.ts", - "groupTitle": "U2F", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - }, - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "identity_token", - "description": "

The one-time identity validation token provided in the email.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "content", - "description": "

The content of the page.

" - } - ] - } - }, - "error": { - "fields": { - "Error 403": [ - { - "group": "Error 403", - "optional": false, - "field": "AccessDenied", - "description": "

Access is denied.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - } - }, - { - "type": "get", - "url": "/api/u2f/sign_request", - "title": "Start U2F authentication", - "name": "StartU2FAuthentication", - "group": "U2F", - "version": "1.0.0", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "optional": false, - "field": "authentication_request", - "description": "

The U2F authentication request.

" - } - ] - } - }, - "error": { - "fields": { - "Error 401": [ - { - "group": "Error 401", - "type": "none", - "optional": false, - "field": "error", - "description": "

There is no key registered for user in session.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - }, - "description": "

Initiate an authentication request using a U2F device.

", - "filename": "shared/api.ts", - "groupTitle": "U2F", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - } - }, - { - "type": "get", - "url": "/api/u2f/register_request", - "title": "Start U2F registration", - "name": "StartU2FRegistration", - "group": "U2F", - "version": "1.0.0", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "optional": false, - "field": "authentication_request", - "description": "

The U2F registration request.

" - } - ] - } - }, - "error": { - "fields": { - "Error 403": [ - { - "group": "Error 403", - "type": "none", - "optional": false, - "field": "error", - "description": "

Unexpected identity validation challenge.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - }, - "description": "

Initiate a U2F device registration request.

", - "filename": "shared/api.ts", - "groupTitle": "U2F", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - } - }, - { - "type": "get", - "url": "/api/verify", - "title": "Verify user authentication", - "name": "VerifyAuthentication", - "group": "Verification", - "version": "1.0.0", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "redirect", - "description": "

Optional parameter set to the url where the user is redirected if access is refused. It is mainly used by Traefik that does not control the redirection itself.

" - } - ] - } - }, - "success": { - "fields": { - "Success 204": [ - { - "group": "Success 204", - "optional": false, - "field": "status", - "description": "

The user is authenticated.

" - } - ] - } - }, - "error": { - "fields": { - "Error 302": [ - { - "group": "Error 302", - "optional": false, - "field": "redirect", - "description": "

The user is redirected if redirect parameter is provided.

" - } - ], - "Error 401": [ - { - "group": "Error 401", - "optional": false, - "field": "status", - "description": "

The user get an error if access failed

" - } - ] - } - }, - "description": "

Verify that the user is authenticated, i.e., the two factors have been validated. If the user is authenticated the response headers Remote-User and Remote-Groups are set. Remote-User contains the user id of the currently logged in user and Remote-Groups a comma separated list of assigned groups.

", - "filename": "shared/api.ts", - "groupTitle": "Verification", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - } - } -] }); diff --git a/doc/api_data.json b/doc/api_data.json deleted file mode 100644 index c6935ffe7..000000000 --- a/doc/api_data.json +++ /dev/null @@ -1,996 +0,0 @@ -[ - { - "type": "get", - "url": "/", - "title": "First factor page", - "name": "Login", - "group": "Authentication", - "version": "1.0.0", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "Content", - "description": "

The content of the first factor page.

" - } - ] - } - }, - "description": "

Serves the login page and create a create a cookie for the client.

", - "filename": "shared/api.ts", - "groupTitle": "Authentication" - }, - { - "type": "get", - "url": "/logout", - "title": "Serves logout page", - "name": "Logout", - "group": "Authentication", - "version": "1.0.0", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "redirect", - "description": "

Redirect to this URL when user is deauthenticated.

" - } - ] - } - }, - "success": { - "fields": { - "Success 302": [ - { - "group": "Success 302", - "optional": false, - "field": "redirect", - "description": "

Redirect to the URL.

" - } - ] - } - }, - "description": "

Log out the user and redirect to the URL.

", - "filename": "shared/api.ts", - "groupTitle": "Authentication" - }, - { - "type": "get", - "url": "/secondfactor", - "title": "Second factor page", - "name": "SecondFactor", - "group": "Authentication", - "version": "1.0.0", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "Content", - "description": "

The content of second factor page.

" - } - ] - } - }, - "description": "

Serves the second factor page

", - "filename": "shared/api.ts", - "groupTitle": "Authentication" - }, - { - "type": "post", - "url": "/1stfactor", - "title": "Bind user against LDAP", - "name": "ValidateFirstFactor", - "group": "Authentication", - "version": "1.0.0", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "username", - "description": "

User username.

" - }, - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "password", - "description": "

User password.

" - } - ] - } - }, - "success": { - "fields": { - "Success 204": [ - { - "group": "Success 204", - "optional": false, - "field": "status", - "description": "

1st factor is validated.

" - } - ] - } - }, - "error": { - "fields": { - "Error 401": [ - { - "group": "Error 401", - "type": "none", - "optional": false, - "field": "error", - "description": "

1st factor is not validated.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - }, - "description": "

Verify credentials against the LDAP.

", - "filename": "shared/api.ts", - "groupTitle": "Authentication", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - } - }, - { - "type": "post", - "url": "/reset-password/request", - "title": "Finish password reset request", - "name": "FinishPasswordResetRequest", - "group": "PasswordReset", - "version": "1.0.0", - "description": "

Start password reset request.

", - "filename": "shared/api.ts", - "groupTitle": "PasswordReset", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - }, - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "identity_token", - "description": "

The one-time identity validation token provided in the email.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "content", - "description": "

The content of the page.

" - } - ] - } - }, - "error": { - "fields": { - "Error 403": [ - { - "group": "Error 403", - "optional": false, - "field": "AccessDenied", - "description": "

Access is denied.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - } - }, - { - "type": "get", - "url": "/password-reset/request", - "title": "Request username", - "name": "ServePasswordResetPage", - "group": "PasswordReset", - "version": "1.0.0", - "description": "

Serve a page that requires the username.

", - "filename": "shared/api.ts", - "groupTitle": "PasswordReset", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - } - }, - { - "type": "post", - "url": "/api/password-reset", - "title": "Set new password", - "name": "SetNewLDAPPassword", - "group": "PasswordReset", - "version": "1.0.0", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "password", - "description": "

New password

" - } - ] - } - }, - "description": "

Set a new password for the user.

", - "filename": "shared/api.ts", - "groupTitle": "PasswordReset", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - } - }, - { - "type": "get", - "url": "/password-reset/identity/start", - "title": "Start password reset request", - "name": "StartPasswordResetRequest", - "group": "PasswordReset", - "version": "1.0.0", - "description": "

Start password reset request.

", - "filename": "shared/api.ts", - "groupTitle": "PasswordReset", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - }, - "success": { - "fields": { - "Success 204": [ - { - "group": "Success 204", - "optional": false, - "field": "status", - "description": "

Identity validation has been initiated.

" - } - ] - } - }, - "error": { - "fields": { - "Error 403": [ - { - "group": "Error 403", - "optional": false, - "field": "AccessDenied", - "description": "

Access is denied.

" - } - ], - "Error 400": [ - { - "group": "Error 400", - "optional": false, - "field": "InvalidIdentity", - "description": "

User identity is invalid.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - } - }, - { - "type": "get", - "url": "/secondfactor/totp/identity/finish", - "title": "Finish TOTP registration identity validation", - "name": "FinishTOTPRegistration", - "group": "TOTP", - "version": "1.0.0", - "description": "

Serves the TOTP registration page that displays the secret. The secret is a QRCode and a base32 secret.

", - "filename": "shared/api.ts", - "groupTitle": "TOTP", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - }, - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "identity_token", - "description": "

The one-time identity validation token provided in the email.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "content", - "description": "

The content of the page.

" - } - ] - } - }, - "error": { - "fields": { - "Error 403": [ - { - "group": "Error 403", - "optional": false, - "field": "AccessDenied", - "description": "

Access is denied.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - } - }, - { - "type": "get", - "url": "/secondfactor/totp/identity/start", - "title": "Start TOTP registration identity validation", - "name": "StartTOTPRegistration", - "group": "TOTP", - "version": "1.0.0", - "description": "

Initiates the identity validation

", - "filename": "shared/api.ts", - "groupTitle": "TOTP", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - }, - "success": { - "fields": { - "Success 204": [ - { - "group": "Success 204", - "optional": false, - "field": "status", - "description": "

Identity validation has been initiated.

" - } - ] - } - }, - "error": { - "fields": { - "Error 403": [ - { - "group": "Error 403", - "optional": false, - "field": "AccessDenied", - "description": "

Access is denied.

" - } - ], - "Error 400": [ - { - "group": "Error 400", - "optional": false, - "field": "InvalidIdentity", - "description": "

User identity is invalid.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - } - }, - { - "type": "post", - "url": "/api/totp", - "title": "Complete TOTP authentication", - "name": "ValidateTOTPSecondFactor", - "group": "TOTP", - "version": "1.0.0", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "token", - "description": "

TOTP token.

" - } - ] - } - }, - "success": { - "fields": { - "Success 302": [ - { - "group": "Success 302", - "optional": false, - "field": "Redirect", - "description": "

to the URL that has been stored during last call to /api/verify.

" - } - ] - } - }, - "error": { - "fields": { - "Error 401": [ - { - "group": "Error 401", - "type": "none", - "optional": false, - "field": "error", - "description": "

TOTP token is invalid.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - }, - "description": "

Verify TOTP token. The user is authenticated upon success.

", - "filename": "shared/api.ts", - "groupTitle": "TOTP", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - } - }, - { - "type": "post", - "url": "/api/u2f/sign", - "title": "Complete U2F authentication", - "name": "CompleteU2FAuthentication", - "group": "U2F", - "version": "1.0.0", - "success": { - "fields": { - "Success 302": [ - { - "group": "Success 302", - "optional": false, - "field": "Redirect", - "description": "

to the URL that has been stored during last call to /api/verify.

" - } - ] - } - }, - "error": { - "fields": { - "Error 403": [ - { - "group": "Error 403", - "type": "none", - "optional": false, - "field": "error", - "description": "

No authentication request has been provided.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - }, - "description": "

Complete authentication request of the U2F device.

", - "filename": "shared/api.ts", - "groupTitle": "U2F", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - } - }, - { - "type": "post", - "url": "/api/secondfactor/u2f/register", - "title": "Complete U2F registration", - "name": "FinishU2FRegistration", - "group": "U2F", - "version": "1.0.0", - "success": { - "fields": { - "Success 302": [ - { - "group": "Success 302", - "optional": false, - "field": "Redirect", - "description": "

to the URL that has been stored during last call to /api/verify.

" - } - ] - } - }, - "description": "

Complete U2F registration request.

", - "filename": "shared/api.ts", - "groupTitle": "U2F", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - }, - "error": { - "fields": { - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - } - }, - { - "type": "get", - "url": "/secondfactor/u2f/identity/start", - "title": "Start U2F registration identity validation", - "name": "RequestU2FRegistration", - "group": "U2F", - "version": "1.0.0", - "filename": "shared/api.ts", - "groupTitle": "U2F", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - }, - "success": { - "fields": { - "Success 204": [ - { - "group": "Success 204", - "optional": false, - "field": "status", - "description": "

Identity validation has been initiated.

" - } - ] - } - }, - "error": { - "fields": { - "Error 403": [ - { - "group": "Error 403", - "optional": false, - "field": "AccessDenied", - "description": "

Access is denied.

" - } - ], - "Error 400": [ - { - "group": "Error 400", - "optional": false, - "field": "InvalidIdentity", - "description": "

User identity is invalid.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - }, - "description": "

This request issue an identity validation token for the user bound to the session. It sends a challenge to the email address set in the user LDAP entry. The user must visit the sent URL to complete the validation and continue the registration process.

" - }, - { - "type": "get", - "url": "/secondfactor/u2f/identity/finish", - "title": "Finish U2F registration identity validation", - "name": "ServeU2FRegistrationPage", - "group": "U2F", - "version": "1.0.0", - "description": "

Serves the U2F registration page that asks the user to touch the token of the U2F device.

", - "filename": "shared/api.ts", - "groupTitle": "U2F", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - }, - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "identity_token", - "description": "

The one-time identity validation token provided in the email.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "content", - "description": "

The content of the page.

" - } - ] - } - }, - "error": { - "fields": { - "Error 403": [ - { - "group": "Error 403", - "optional": false, - "field": "AccessDenied", - "description": "

Access is denied.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - } - }, - { - "type": "get", - "url": "/api/u2f/sign_request", - "title": "Start U2F authentication", - "name": "StartU2FAuthentication", - "group": "U2F", - "version": "1.0.0", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "optional": false, - "field": "authentication_request", - "description": "

The U2F authentication request.

" - } - ] - } - }, - "error": { - "fields": { - "Error 401": [ - { - "group": "Error 401", - "type": "none", - "optional": false, - "field": "error", - "description": "

There is no key registered for user in session.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - }, - "description": "

Initiate an authentication request using a U2F device.

", - "filename": "shared/api.ts", - "groupTitle": "U2F", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - } - }, - { - "type": "get", - "url": "/api/u2f/register_request", - "title": "Start U2F registration", - "name": "StartU2FRegistration", - "group": "U2F", - "version": "1.0.0", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "optional": false, - "field": "authentication_request", - "description": "

The U2F registration request.

" - } - ] - } - }, - "error": { - "fields": { - "Error 403": [ - { - "group": "Error 403", - "type": "none", - "optional": false, - "field": "error", - "description": "

Unexpected identity validation challenge.

" - } - ], - "Error 500": [ - { - "group": "Error 500", - "type": "String", - "optional": false, - "field": "error", - "description": "

Internal error message.

" - } - ] - } - }, - "description": "

Initiate a U2F device registration request.

", - "filename": "shared/api.ts", - "groupTitle": "U2F", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - } - }, - { - "type": "get", - "url": "/api/verify", - "title": "Verify user authentication", - "name": "VerifyAuthentication", - "group": "Verification", - "version": "1.0.0", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "redirect", - "description": "

Optional parameter set to the url where the user is redirected if access is refused. It is mainly used by Traefik that does not control the redirection itself.

" - } - ] - } - }, - "success": { - "fields": { - "Success 204": [ - { - "group": "Success 204", - "optional": false, - "field": "status", - "description": "

The user is authenticated.

" - } - ] - } - }, - "error": { - "fields": { - "Error 302": [ - { - "group": "Error 302", - "optional": false, - "field": "redirect", - "description": "

The user is redirected if redirect parameter is provided.

" - } - ], - "Error 401": [ - { - "group": "Error 401", - "optional": false, - "field": "status", - "description": "

The user get an error if access failed

" - } - ] - } - }, - "description": "

Verify that the user is authenticated, i.e., the two factors have been validated. If the user is authenticated the response headers Remote-User and Remote-Groups are set. Remote-User contains the user id of the currently logged in user and Remote-Groups a comma separated list of assigned groups.

", - "filename": "shared/api.ts", - "groupTitle": "Verification", - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Cookie", - "description": "

Cookie containing "connect.sid", the user session token.

" - } - ] - } - } - } -] diff --git a/doc/api_project.js b/doc/api_project.js deleted file mode 100644 index 727258a09..000000000 --- a/doc/api_project.js +++ /dev/null @@ -1,15 +0,0 @@ -define({ - "title": "Authelia API documentation", - "name": "authelia", - "version": "3.7.0", - "description": "2FA Single Sign-On server for nginx using LDAP, TOTP and U2F", - "sampleUrl": false, - "defaultVersion": "0.0.0", - "apidoc": "0.3.0", - "generator": { - "name": "apidoc", - "time": "2017-12-04T21:38:44.927Z", - "url": "http://apidocjs.com", - "version": "0.17.6" - } -}); diff --git a/doc/api_project.json b/doc/api_project.json deleted file mode 100644 index a3017b24f..000000000 --- a/doc/api_project.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "title": "Authelia API documentation", - "name": "authelia", - "version": "3.7.0", - "description": "2FA Single Sign-On server for nginx using LDAP, TOTP and U2F", - "sampleUrl": false, - "defaultVersion": "0.0.0", - "apidoc": "0.3.0", - "generator": { - "name": "apidoc", - "time": "2017-12-04T21:38:44.927Z", - "url": "http://apidocjs.com", - "version": "0.17.6" - } -} diff --git a/doc/css/style.css b/doc/css/style.css deleted file mode 100644 index 6468b2b22..000000000 --- a/doc/css/style.css +++ /dev/null @@ -1,569 +0,0 @@ -/* ------------------------------------------------------------------------------------------ - * Content - * ------------------------------------------------------------------------------------------ */ -body { - min-width: 980px; - max-width: 1280px; -} - -body, p, a, div, th, td { - font-family: "Source Sans Pro", sans-serif; - font-weight: 400; - font-size: 16px; -} - -td.code { - font-size: 14px; - font-family: "Source Code Pro", monospace; - font-style: normal; - font-weight: 400; -} - -#content { - padding-top: 16px; - z-Index: -1; - margin-left: 270px; -} - -p { - color: #808080; -} - -h1 { - font-family: "Source Sans Pro Semibold", sans-serif; - font-weight: normal; - font-size: 44px; - line-height: 50px; - margin: 0 0 10px 0; - padding: 0; -} - -h2 { - font-family: "Source Sans Pro", sans-serif; - font-weight: normal; - font-size: 24px; - line-height: 40px; - margin: 0 0 20px 0; - padding: 0; -} - -section { - border-top: 1px solid #ebebeb; - padding: 30px 0; -} - -section h1 { - font-family: "Source Sans Pro", sans-serif; - font-weight: 700; - font-size: 32px; - line-height: 40px; - padding-bottom: 14px; - margin: 0 0 20px 0; - padding: 0; -} - -article { - padding: 14px 0 30px 0; -} - -article h1 { - font-family: "Source Sans Pro Bold", sans-serif; - font-weight: 600; - font-size: 24px; - line-height: 26px; -} - -article h2 { - font-family: "Source Sans Pro", sans-serif; - font-weight: 600; - font-size: 18px; - line-height: 24px; - margin: 0 0 10px 0; -} - -article h3 { - font-family: "Source Sans Pro", sans-serif; - font-weight: 600; - font-size: 16px; - line-height: 18px; - margin: 0 0 10px 0; -} - -article h4 { - font-family: "Source Sans Pro", sans-serif; - font-weight: 600; - font-size: 14px; - line-height: 16px; - margin: 0 0 8px 0; -} - -table { - border-collapse: collapse; - width: 100%; - margin: 0 0 20px 0; -} - -th { - background-color: #f5f5f5; - text-align: left; - font-family: "Source Sans Pro", sans-serif; - font-weight: 700; - padding: 4px 8px; - border: #e0e0e0 1px solid; -} - -td { - vertical-align: top; - padding: 10px 8px 0 8px; - border: #e0e0e0 1px solid; -} - -#generator .content { - color: #b0b0b0; - border-top: 1px solid #ebebeb; - padding: 10px 0; -} - -.label-optional { - float: right; - background-color: grey; - margin-top: 4px; -} - -.open-left { - right: 0; - left: auto; -} - -/* ------------------------------------------------------------------------------------------ - * apidoc - intro - * ------------------------------------------------------------------------------------------ */ - -#apidoc .apidoc { - border-top: 1px solid #ebebeb; - padding: 30px 0; -} - -#apidoc h1 { - font-family: "Source Sans Pro", sans-serif; - font-weight: 700; - font-size: 32px; - line-height: 40px; - padding-bottom: 14px; - margin: 0 0 20px 0; - padding: 0; -} - -#apidoc h2 { - font-family: "Source Sans Pro Bold", sans-serif; - font-weight: 600; - font-size: 22px; - line-height: 26px; - padding-top: 14px; -} - -/* ------------------------------------------------------------------------------------------ - * pre / code - * ------------------------------------------------------------------------------------------ */ -pre { - background-color: #292b36; - color: #ffffff; - padding: 10px; - border-radius: 6px; - position: relative; - margin: 10px 0 20px 0; - overflow-x: auto; -} - -pre.prettyprint { - width: 100%; -} - -code.language-text { - word-wrap: break-word; -} - -pre.language-json { - overflow: auto; -} - -pre.language-html { - margin: 0 0 20px 0; -} - -.type { - font-family: "Source Sans Pro", sans-serif; - font-weight: 600; - font-size: 15px; - display: inline-block; - margin: 0 0 5px 0; - padding: 4px 5px; - border-radius: 6px; - text-transform: uppercase; - background-color: #3387CC; - color: #ffffff; -} - -.type__get { - background-color: green; -} - -.type__put { - background-color: #e5c500; -} - -.type__post { - background-color: #4070ec; -} - -.type__delete { - background-color: #ed0039; -} - -pre.language-api .str { - color: #ffffff; -} - -pre.language-api .pln, -pre.language-api .pun { - color: #65B042; -} - -pre code { - display: block; - font-size: 14px; - font-family: "Source Code Pro", monospace; - font-style: normal; - font-weight: 400; - word-wrap: normal; - white-space: pre; -} - -pre code.sample-request-response-json { - white-space: pre-wrap; - max-height: 500px; - overflow: auto; -} - -/* ------------------------------------------------------------------------------------------ - * Sidenav - * ------------------------------------------------------------------------------------------ */ -.sidenav { - width: 228px; - margin: 0; - padding: 0 20px 20px 20px; - position: fixed; - top: 50px; - left: 0; - bottom: 0; - overflow-x: hidden; - overflow-y: auto; - background-color: #f5f5f5; - z-index: 10; -} - -.sidenav > li > a { - display: block; - width: 192px; - margin: 0; - padding: 2px 11px; - border: 0; - border-left: transparent 4px solid; - border-right: transparent 4px solid; - font-family: "Source Sans Pro", sans-serif; - font-weight: 400; - font-size: 14px; -} - -.sidenav > li.nav-header { - margin-top: 8px; - margin-bottom: 8px; -} - -.sidenav > li.nav-header > a { - padding: 5px 15px; - border: 1px solid #e5e5e5; - width: 190px; - font-family: "Source Sans Pro", sans-serif; - font-weight: 700; - font-size: 16px; - background-color: #ffffff; -} - -.sidenav > li.active > a { - position: relative; - z-index: 2; - background-color: #0088cc; - color: #ffffff; -} - -.sidenav > li.has-modifications a { - border-right: #60d060 4px solid; -} - -.sidenav > li.is-new a { - border-left: #e5e5e5 4px solid; -} - -/* ------------------------------------------------------------------------------------------ - * Side nav search - * ------------------------------------------------------------------------------------------ */ -.sidenav-search { - width: 228px; - left: 0px; - position: fixed; - padding: 16px 20px 10px 20px; - background-color: #F5F5F5; - z-index: 11; -} - -.sidenav-search .search { - height: 26px; -} - -.search-reset { - position: absolute; - display: block; - cursor: pointer; - width: 20px; - height: 20px; - text-align: center; - right: 28px; - top: 17px; - background-color: #fff; -} - -/* ------------------------------------------------------------------------------------------ - * Compare - * ------------------------------------------------------------------------------------------ */ - -ins { - background: #60d060; - text-decoration: none; - color: #000000; -} - -del { - background: #f05050; - color: #000000; -} - -.label-ins { - background-color: #60d060; -} - -.label-del { - background-color: #f05050; - text-decoration: line-through; -} - -pre.ins { - background-color: #60d060; -} - -pre.del { - background-color: #f05050; - text-decoration: line-through; -} - -table.ins th, -table.ins td { - background-color: #60d060; -} - -table.del th, -table.del td { - background-color: #f05050; - text-decoration: line-through; -} - -tr.ins td { - background-color: #60d060; -} - -tr.del td { - background-color: #f05050; - text-decoration: line-through; -} - -/* ------------------------------------------------------------------------------------------ - * Spinner - * ------------------------------------------------------------------------------------------ */ - -#loader { - position: absolute; - width: 100%; -} - -#loader p { - padding-top: 80px; - margin-left: -4px; -} - -.spinner { - margin: 200px auto; - width: 60px; - height: 60px; - position: relative; -} - -.container1 > div, .container2 > div, .container3 > div { - width: 14px; - height: 14px; - background-color: #0088cc; - - border-radius: 100%; - position: absolute; - -webkit-animation: bouncedelay 1.2s infinite ease-in-out; - animation: bouncedelay 1.2s infinite ease-in-out; - /* Prevent first frame from flickering when animation starts */ - -webkit-animation-fill-mode: both; - animation-fill-mode: both; -} - -.spinner .spinner-container { - position: absolute; - width: 100%; - height: 100%; -} - -.container2 { - -webkit-transform: rotateZ(45deg); - transform: rotateZ(45deg); -} - -.container3 { - -webkit-transform: rotateZ(90deg); - transform: rotateZ(90deg); -} - -.circle1 { top: 0; left: 0; } -.circle2 { top: 0; right: 0; } -.circle3 { right: 0; bottom: 0; } -.circle4 { left: 0; bottom: 0; } - -.container2 .circle1 { - -webkit-animation-delay: -1.1s; - animation-delay: -1.1s; -} - -.container3 .circle1 { - -webkit-animation-delay: -1.0s; - animation-delay: -1.0s; -} - -.container1 .circle2 { - -webkit-animation-delay: -0.9s; - animation-delay: -0.9s; -} - -.container2 .circle2 { - -webkit-animation-delay: -0.8s; - animation-delay: -0.8s; -} - -.container3 .circle2 { - -webkit-animation-delay: -0.7s; - animation-delay: -0.7s; -} - -.container1 .circle3 { - -webkit-animation-delay: -0.6s; - animation-delay: -0.6s; -} - -.container2 .circle3 { - -webkit-animation-delay: -0.5s; - animation-delay: -0.5s; -} - -.container3 .circle3 { - -webkit-animation-delay: -0.4s; - animation-delay: -0.4s; -} - -.container1 .circle4 { - -webkit-animation-delay: -0.3s; - animation-delay: -0.3s; -} - -.container2 .circle4 { - -webkit-animation-delay: -0.2s; - animation-delay: -0.2s; -} - -.container3 .circle4 { - -webkit-animation-delay: -0.1s; - animation-delay: -0.1s; -} - -@-webkit-keyframes bouncedelay { - 0%, 80%, 100% { -webkit-transform: scale(0.0) } - 40% { -webkit-transform: scale(1.0) } -} - -@keyframes bouncedelay { - 0%, 80%, 100% { - transform: scale(0.0); - -webkit-transform: scale(0.0); - } 40% { - transform: scale(1.0); - -webkit-transform: scale(1.0); - } -} - -/* ------------------------------------------------------------------------------------------ - * Tabs - * ------------------------------------------------------------------------------------------ */ -ul.nav-tabs { - margin: 0; -} - -p.deprecated span{ - color: #ff0000; - font-weight: bold; - text-decoration: underline; -} - -/* ------------------------------------------------------------------------------------------ - * Print - * ------------------------------------------------------------------------------------------ */ - -@media print { - - #sidenav, - #version, - #versions, - section .version, - section .versions { - display: none; - } - - #content { - margin-left: 0; - } - - a { - text-decoration: none; - color: inherit; - } - - a:after { - content: " [" attr(href) "] "; - } - - p { - color: #000000 - } - - pre { - background-color: #ffffff; - color: #000000; - padding: 10px; - border: #808080 1px solid; - border-radius: 6px; - position: relative; - margin: 10px 0 20px 0; - } - -} /* /@media print */ diff --git a/doc/fonts/glyphicons-halflings-regular.eot b/doc/fonts/glyphicons-halflings-regular.eot deleted file mode 100644 index b93a4953fff68df523aa7656497ee339d6026d64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20127 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/doc/fonts/glyphicons-halflings-regular.ttf b/doc/fonts/glyphicons-halflings-regular.ttf deleted file mode 100644 index 1413fc609ab6f21774de0cb7e01360095584f65b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45404 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 G`u_lkUM?>H diff --git a/doc/fonts/glyphicons-halflings-regular.woff2 b/doc/fonts/glyphicons-halflings-regular.woff2 deleted file mode 100644 index 64539b54c3751a6d9adb44c8e3a45ba5a73b77f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18028 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 diff --git a/doc/img/favicon.ico b/doc/img/favicon.ico deleted file mode 100644 index c307a043933f0e860284157007820fccbe0fc96f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 894 zcmdUuF-rqM6ojAn2d)y!l(7l<0Sa4)bsGCC1jQ;~7c8z2NtY8s$`~6pMGzDegoNu- zL@-!L!~}wc5V437IkY*y&4xu5e}L}I?#-JU-p($Z$Q+O73G1S4&5JCENScWxDW=x- zP<(U8O;P?D)-rOqJxf*D5X#fMtSq@XeWi86$CGh&FK141Qt~NVWtAj}bFN-DLPvaT z*RIZLGz1Vz2nbHj-L#d^{{!N!&pBAbk2j(^U(2=VbJTML#&?*0s93%{?MEL%tQGVj{yYS9qIdd y=|=!E>V$}|g9zOiSnsP@V9MK)_i(HXtO!B3{(nl`|3Ly2=CXc=hEFxke;MD%5Rt_I diff --git a/doc/index.html b/doc/index.html deleted file mode 100644 index 5f04deda5..000000000 --- a/doc/index.html +++ /dev/null @@ -1,669 +0,0 @@ - - - - - Loading... - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
- -
- -
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-

Loading...

-
-
- - - - diff --git a/doc/locales/ca.js b/doc/locales/ca.js deleted file mode 100644 index 65af5df2b..000000000 --- a/doc/locales/ca.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - ca: { - 'Allowed values:' : 'Valors permesos:', - 'Compare all with predecessor': 'Comparar tot amb versió anterior', - 'compare changes to:' : 'comparar canvis amb:', - 'compared to' : 'comparat amb', - 'Default value:' : 'Valor per defecte:', - 'Description' : 'Descripció', - 'Field' : 'Camp', - 'General' : 'General', - 'Generated with' : 'Generat amb', - 'Name' : 'Nom', - 'No response values.' : 'Sense valors en la resposta.', - 'optional' : 'opcional', - 'Parameter' : 'Paràmetre', - 'Permission:' : 'Permisos:', - 'Response' : 'Resposta', - 'Send' : 'Enviar', - 'Send a Sample Request' : 'Enviar una petició d\'exemple', - 'show up to version:' : 'mostrar versió:', - 'Size range:' : 'Tamany de rang:', - 'Type' : 'Tipus', - 'url' : 'url' - } -}); diff --git a/doc/locales/de.js b/doc/locales/de.js deleted file mode 100644 index f66420d00..000000000 --- a/doc/locales/de.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - de: { - 'Allowed values:' : 'Erlaubte Werte:', - 'Compare all with predecessor': 'Vergleiche alle mit ihren Vorgängern', - 'compare changes to:' : 'vergleiche Änderungen mit:', - 'compared to' : 'verglichen mit', - 'Default value:' : 'Standardwert:', - 'Description' : 'Beschreibung', - 'Field' : 'Feld', - 'General' : 'Allgemein', - 'Generated with' : 'Erstellt mit', - 'Name' : 'Name', - 'No response values.' : 'Keine Rückgabewerte.', - 'optional' : 'optional', - 'Parameter' : 'Parameter', - 'Permission:' : 'Berechtigung:', - 'Response' : 'Antwort', - 'Send' : 'Senden', - 'Send a Sample Request' : 'Eine Beispielanfrage senden', - 'show up to version:' : 'zeige bis zur Version:', - 'Size range:' : 'Größenbereich:', - 'Type' : 'Typ', - 'url' : 'url' - } -}); diff --git a/doc/locales/es.js b/doc/locales/es.js deleted file mode 100644 index 3d47e800e..000000000 --- a/doc/locales/es.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - es: { - 'Allowed values:' : 'Valores permitidos:', - 'Compare all with predecessor': 'Comparar todo con versión anterior', - 'compare changes to:' : 'comparar cambios con:', - 'compared to' : 'comparado con', - 'Default value:' : 'Valor por defecto:', - 'Description' : 'Descripción', - 'Field' : 'Campo', - 'General' : 'General', - 'Generated with' : 'Generado con', - 'Name' : 'Nombre', - 'No response values.' : 'Sin valores en la respuesta.', - 'optional' : 'opcional', - 'Parameter' : 'Parámetro', - 'Permission:' : 'Permisos:', - 'Response' : 'Respuesta', - 'Send' : 'Enviar', - 'Send a Sample Request' : 'Enviar una petición de ejemplo', - 'show up to version:' : 'mostrar a versión:', - 'Size range:' : 'Tamaño de rango:', - 'Type' : 'Tipo', - 'url' : 'url' - } -}); diff --git a/doc/locales/fr.js b/doc/locales/fr.js deleted file mode 100644 index 100a64291..000000000 --- a/doc/locales/fr.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - fr: { - 'Allowed values:' : 'Valeurs autorisées :', - 'Compare all with predecessor': 'Tout comparer avec ...', - 'compare changes to:' : 'comparer les changements à :', - 'compared to' : 'comparer à', - 'Default value:' : 'Valeur par défaut :', - 'Description' : 'Description', - 'Field' : 'Champ', - 'General' : 'Général', - 'Generated with' : 'Généré avec', - 'Name' : 'Nom', - 'No response values.' : 'Aucune valeur de réponse.', - 'optional' : 'optionnel', - 'Parameter' : 'Paramètre', - 'Permission:' : 'Permission :', - 'Response' : 'Réponse', - 'Send' : 'Envoyer', - 'Send a Sample Request' : 'Envoyer une requête représentative', - 'show up to version:' : 'Montrer à partir de la version :', - 'Size range:' : 'Ordre de grandeur :', - 'Type' : 'Type', - 'url' : 'url' - } -}); diff --git a/doc/locales/it.js b/doc/locales/it.js deleted file mode 100644 index 8117108cf..000000000 --- a/doc/locales/it.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - it: { - 'Allowed values:' : 'Valori permessi:', - 'Compare all with predecessor': 'Confronta tutto con versioni precedenti', - 'compare changes to:' : 'confronta modifiche con:', - 'compared to' : 'confrontato con', - 'Default value:' : 'Valore predefinito:', - 'Description' : 'Descrizione', - 'Field' : 'Campo', - 'General' : 'Generale', - 'Generated with' : 'Creato con', - 'Name' : 'Nome', - 'No response values.' : 'Nessun valore di risposta.', - 'optional' : 'opzionale', - 'Parameter' : 'Parametro', - 'Permission:' : 'Permessi:', - 'Response' : 'Risposta', - 'Send' : 'Invia', - 'Send a Sample Request' : 'Invia una richiesta di esempio', - 'show up to version:' : 'mostra alla versione:', - 'Size range:' : 'Intervallo dimensione:', - 'Type' : 'Tipo', - 'url' : 'url' - } -}); diff --git a/doc/locales/locale.js b/doc/locales/locale.js deleted file mode 100644 index ba82385ad..000000000 --- a/doc/locales/locale.js +++ /dev/null @@ -1,50 +0,0 @@ -define([ - './locales/ca.js', - './locales/de.js', - './locales/es.js', - './locales/fr.js', - './locales/it.js', - './locales/nl.js', - './locales/pl.js', - './locales/pt_br.js', - './locales/ro.js', - './locales/ru.js', - './locales/tr.js', - './locales/vi.js', - './locales/zh.js', - './locales/zh_cn.js' -], function() { - var langId = (navigator.language || navigator.userLanguage).toLowerCase().replace('-', '_'); - var language = langId.substr(0, 2); - var locales = {}; - - for (index in arguments) { - for (property in arguments[index]) - locales[property] = arguments[index][property]; - } - if ( ! locales['en']) - locales['en'] = {}; - - if ( ! locales[langId] && ! locales[language]) - language = 'en'; - - var locale = (locales[langId] ? locales[langId] : locales[language]); - - function __(text) { - var index = locale[text]; - if (index === undefined) - return text; - return index; - }; - - function setLanguage(language) { - locale = locales[language]; - } - - return { - __ : __, - locales : locales, - locale : locale, - setLanguage: setLanguage - }; -}); diff --git a/doc/locales/nl.js b/doc/locales/nl.js deleted file mode 100644 index bddfeeb18..000000000 --- a/doc/locales/nl.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - nl: { - 'Allowed values:' : 'Toegestane waarden:', - 'Compare all with predecessor': 'Vergelijk alle met voorgaande versie', - 'compare changes to:' : 'vergelijk veranderingen met:', - 'compared to' : 'vergelijk met', - 'Default value:' : 'Standaard waarde:', - 'Description' : 'Omschrijving', - 'Field' : 'Veld', - 'General' : 'Algemeen', - 'Generated with' : 'Gegenereerd met', - 'Name' : 'Naam', - 'No response values.' : 'Geen response waardes.', - 'optional' : 'optioneel', - 'Parameter' : 'Parameter', - 'Permission:' : 'Permissie:', - 'Response' : 'Antwoorden', - 'Send' : 'Sturen', - 'Send a Sample Request' : 'Stuur een sample aanvragen', - 'show up to version:' : 'toon tot en met versie:', - 'Size range:' : 'Maatbereik:', - 'Type' : 'Type', - 'url' : 'url' - } -}); diff --git a/doc/locales/pl.js b/doc/locales/pl.js deleted file mode 100644 index db645ee16..000000000 --- a/doc/locales/pl.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - pl: { - 'Allowed values:' : 'Dozwolone wartości:', - 'Compare all with predecessor': 'Porównaj z poprzednimi wersjami', - 'compare changes to:' : 'porównaj zmiany do:', - 'compared to' : 'porównaj do:', - 'Default value:' : 'Wartość domyślna:', - 'Description' : 'Opis', - 'Field' : 'Pole', - 'General' : 'Generalnie', - 'Generated with' : 'Wygenerowano z', - 'Name' : 'Nazwa', - 'No response values.' : 'Brak odpowiedzi.', - 'optional' : 'opcjonalny', - 'Parameter' : 'Parametr', - 'Permission:' : 'Uprawnienia:', - 'Response' : 'Odpowiedź', - 'Send' : 'Wyślij', - 'Send a Sample Request' : 'Wyślij przykładowe żądanie', - 'show up to version:' : 'pokaż do wersji:', - 'Size range:' : 'Zakres rozmiaru:', - 'Type' : 'Typ', - 'url' : 'url' - } -}); diff --git a/doc/locales/pt_br.js b/doc/locales/pt_br.js deleted file mode 100644 index 2bd78b0d3..000000000 --- a/doc/locales/pt_br.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - 'pt_br': { - 'Allowed values:' : 'Valores permitidos:', - 'Compare all with predecessor': 'Compare todos com antecessores', - 'compare changes to:' : 'comparar alterações com:', - 'compared to' : 'comparado com', - 'Default value:' : 'Valor padrão:', - 'Description' : 'Descrição', - 'Field' : 'Campo', - 'General' : 'Geral', - 'Generated with' : 'Gerado com', - 'Name' : 'Nome', - 'No response values.' : 'Sem valores de resposta.', - 'optional' : 'opcional', - 'Parameter' : 'Parâmetro', - 'Permission:' : 'Permissão:', - 'Response' : 'Resposta', - 'Send' : 'Enviar', - 'Send a Sample Request' : 'Enviar um Exemplo de Pedido', - 'show up to version:' : 'aparecer para a versão:', - 'Size range:' : 'Faixa de tamanho:', - 'Type' : 'Tipo', - 'url' : 'url' - } -}); diff --git a/doc/locales/ro.js b/doc/locales/ro.js deleted file mode 100644 index 8d4e4ed87..000000000 --- a/doc/locales/ro.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - ro: { - 'Allowed values:' : 'Valori permise:', - 'Compare all with predecessor': 'Compară toate cu versiunea precedentă', - 'compare changes to:' : 'compară cu versiunea:', - 'compared to' : 'comparat cu', - 'Default value:' : 'Valoare implicită:', - 'Description' : 'Descriere', - 'Field' : 'Câmp', - 'General' : 'General', - 'Generated with' : 'Generat cu', - 'Name' : 'Nume', - 'No response values.' : 'Nici o valoare returnată.', - 'optional' : 'opțional', - 'Parameter' : 'Parametru', - 'Permission:' : 'Permisiune:', - 'Response' : 'Răspuns', - 'Send' : 'Trimite', - 'Send a Sample Request' : 'Trimite o cerere de probă', - 'show up to version:' : 'arată până la versiunea:', - 'Size range:' : 'Interval permis:', - 'Type' : 'Tip', - 'url' : 'url' - } -}); diff --git a/doc/locales/ru.js b/doc/locales/ru.js deleted file mode 100644 index c5f338214..000000000 --- a/doc/locales/ru.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - ru: { - 'Allowed values:' : 'Допустимые значения:', - 'Compare all with predecessor': 'Сравнить с предыдущей версией', - 'compare changes to:' : 'сравнить с:', - 'compared to' : 'в сравнении с', - 'Default value:' : 'По умолчанию:', - 'Description' : 'Описание', - 'Field' : 'Название', - 'General' : 'Общая информация', - 'Generated with' : 'Сгенерировано с помощью', - 'Name' : 'Название', - 'No response values.' : 'Нет значений для ответа.', - 'optional' : 'необязательный', - 'Parameter' : 'Параметр', - 'Permission:' : 'Разрешено:', - 'Response' : 'Ответ', - 'Send' : 'Отправить', - 'Send a Sample Request' : 'Отправить тестовый запрос', - 'show up to version:' : 'показать версию:', - 'Size range:' : 'Ограничения:', - 'Type' : 'Тип', - 'url' : 'URL' - } -}); diff --git a/doc/locales/tr.js b/doc/locales/tr.js deleted file mode 100644 index 5c64e52da..000000000 --- a/doc/locales/tr.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - tr: { - 'Allowed values:' : 'İzin verilen değerler:', - 'Compare all with predecessor': 'Tümünü öncekiler ile karşılaştır', - 'compare changes to:' : 'değişiklikleri karşılaştır:', - 'compared to' : 'karşılaştır', - 'Default value:' : 'Varsayılan değer:', - 'Description' : 'Açıklama', - 'Field' : 'Alan', - 'General' : 'Genel', - 'Generated with' : 'Oluşturan', - 'Name' : 'İsim', - 'No response values.' : 'Dönüş verisi yok.', - 'optional' : 'opsiyonel', - 'Parameter' : 'Parametre', - 'Permission:' : 'İzin:', - 'Response' : 'Dönüş', - 'Send' : 'Gönder', - 'Send a Sample Request' : 'Örnek istek gönder', - 'show up to version:' : 'bu versiyona kadar göster:', - 'Size range:' : 'Boyut aralığı:', - 'Type' : 'Tip', - 'url' : 'url' - } -}); diff --git a/doc/locales/vi.js b/doc/locales/vi.js deleted file mode 100644 index 7ce770507..000000000 --- a/doc/locales/vi.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - vi: { - 'Allowed values:' : 'Giá trị chấp nhận:', - 'Compare all with predecessor': 'So sánh với tất cả phiên bản trước', - 'compare changes to:' : 'so sánh sự thay đổi với:', - 'compared to' : 'so sánh với', - 'Default value:' : 'Giá trị mặc định:', - 'Description' : 'Chú thích', - 'Field' : 'Trường dữ liệu', - 'General' : 'Tổng quan', - 'Generated with' : 'Được tạo bởi', - 'Name' : 'Tên', - 'No response values.' : 'Không có kết quả trả về.', - 'optional' : 'Tùy chọn', - 'Parameter' : 'Tham số', - 'Permission:' : 'Quyền hạn:', - 'Response' : 'Kết quả', - 'Send' : 'Gửi', - 'Send a Sample Request' : 'Gửi một yêu cầu mẫu', - 'show up to version:' : 'hiển thị phiên bản:', - 'Size range:' : 'Kích cỡ:', - 'Type' : 'Kiểu', - 'url' : 'liên kết' - } -}); diff --git a/doc/locales/zh.js b/doc/locales/zh.js deleted file mode 100644 index 66522067f..000000000 --- a/doc/locales/zh.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - zh: { - 'Allowed values​​:' : '允許值:', - 'Compare all with predecessor': '預先比較所有', - 'compare changes to:' : '比較變更:', - 'compared to' : '對比', - 'Default value:' : '默認值:', - 'Description' : '描述', - 'Field' : '字段', - 'General' : '概括', - 'Generated with' : '生成工具', - 'Name' : '名稱', - 'No response values​​.' : '無對應資料.', - 'optional' : '選項', - 'Parameter' : '參數', - 'Permission:' : '允許:', - 'Response' : '回應', - 'Send' : '發送', - 'Send a Sample Request' : '發送試用需求', - 'show up to version:' : '顯示到版本:', - 'Size range:' : '尺寸範圍:', - 'Type' : '類型', - 'url' : '網址' - } -}); diff --git a/doc/locales/zh_cn.js b/doc/locales/zh_cn.js deleted file mode 100644 index 1938ca184..000000000 --- a/doc/locales/zh_cn.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - 'zh_cn': { - 'Allowed values:' : '允许值:', - 'Compare all with predecessor': '与所有较早的比较', - 'compare changes to:' : '将当前版本与指定版本比较:', - 'compared to' : '相比于', - 'Default value:' : '默认值:', - 'Description' : '描述', - 'Field' : '字段', - 'General' : '概要', - 'Generated with' : '基于', - 'Name' : '名称', - 'No response values.' : '无返回值.', - 'optional' : '可选', - 'Parameter' : '参数', - 'Permission:' : '权限:', - 'Response' : '返回', - 'Send' : '发送', - 'Send a Sample Request' : '发送示例请求', - 'show up to version:' : '显示到指定版本:', - 'Size range:' : '取值范围:', - 'Type' : '类型', - 'url' : '网址' - } -}); diff --git a/doc/main.js b/doc/main.js deleted file mode 100644 index 9d31fa5f6..000000000 --- a/doc/main.js +++ /dev/null @@ -1,827 +0,0 @@ -require.config({ - paths: { - bootstrap: './vendor/bootstrap.min', - diffMatchPatch: './vendor/diff_match_patch.min', - handlebars: './vendor/handlebars.min', - handlebarsExtended: './utils/handlebars_helper', - jquery: './vendor/jquery.min', - locales: './locales/locale', - lodash: './vendor/lodash.custom.min', - pathToRegexp: './vendor/path-to-regexp/index', - prettify: './vendor/prettify/prettify', - semver: './vendor/semver.min', - utilsSampleRequest: './utils/send_sample_request', - webfontloader: './vendor/webfontloader', - list: './vendor/list.min' - }, - shim: { - bootstrap: { - deps: ['jquery'] - }, - diffMatchPatch: { - exports: 'diff_match_patch' - }, - handlebars: { - exports: 'Handlebars' - }, - handlebarsExtended: { - deps: ['jquery', 'handlebars'], - exports: 'Handlebars' - }, - prettify: { - exports: 'prettyPrint' - } - }, - urlArgs: 'v=' + (new Date()).getTime(), - waitSeconds: 15 -}); - -require([ - 'jquery', - 'lodash', - 'locales', - 'handlebarsExtended', - './api_project.js', - './api_data.js', - 'prettify', - 'utilsSampleRequest', - 'semver', - 'webfontloader', - 'bootstrap', - 'pathToRegexp', - 'list' -], function($, _, locale, Handlebars, apiProject, apiData, prettyPrint, sampleRequest, semver, WebFont) { - - // load google web fonts - loadGoogleFontCss(); - - var api = apiData.api; - - // - // Templates - // - var templateHeader = Handlebars.compile( $('#template-header').html() ); - var templateFooter = Handlebars.compile( $('#template-footer').html() ); - var templateArticle = Handlebars.compile( $('#template-article').html() ); - var templateCompareArticle = Handlebars.compile( $('#template-compare-article').html() ); - var templateGenerator = Handlebars.compile( $('#template-generator').html() ); - var templateProject = Handlebars.compile( $('#template-project').html() ); - var templateSections = Handlebars.compile( $('#template-sections').html() ); - var templateSidenav = Handlebars.compile( $('#template-sidenav').html() ); - - // - // apiProject defaults - // - if ( ! apiProject.template) - apiProject.template = {}; - - if (apiProject.template.withCompare == null) - apiProject.template.withCompare = true; - - if (apiProject.template.withGenerator == null) - apiProject.template.withGenerator = true; - - if (apiProject.template.forceLanguage) - locale.setLanguage(apiProject.template.forceLanguage); - - // Setup jQuery Ajax - $.ajaxSetup(apiProject.template.jQueryAjaxSetup); - - // - // Data transform - // - // grouped by group - var apiByGroup = _.groupBy(api, function(entry) { - return entry.group; - }); - - // grouped by group and name - var apiByGroupAndName = {}; - $.each(apiByGroup, function(index, entries) { - apiByGroupAndName[index] = _.groupBy(entries, function(entry) { - return entry.name; - }); - }); - - // - // sort api within a group by title ASC and custom order - // - var newList = []; - var umlauts = { 'ä': 'ae', 'ü': 'ue', 'ö': 'oe', 'ß': 'ss' }; // TODO: remove in version 1.0 - $.each (apiByGroupAndName, function(index, groupEntries) { - // get titles from the first entry of group[].name[] (name has versioning) - var titles = []; - $.each (groupEntries, function(titleName, entries) { - var title = entries[0].title; - if(title !== undefined) { - title.toLowerCase().replace(/[äöüß]/g, function($0) { return umlauts[$0]; }); - titles.push(title + '#~#' + titleName); // '#~#' keep reference to titleName after sorting - } - }); - // sort by name ASC - titles.sort(); - - // custom order - if (apiProject.order) - titles = sortByOrder(titles, apiProject.order, '#~#'); - - // add single elements to the new list - titles.forEach(function(name) { - var values = name.split('#~#'); - var key = values[1]; - groupEntries[key].forEach(function(entry) { - newList.push(entry); - }); - }); - }); - // api overwrite with ordered list - api = newList; - - // - // Group- and Versionlists - // - var apiGroups = {}; - var apiGroupTitles = {}; - var apiVersions = {}; - apiVersions[apiProject.version] = 1; - - $.each(api, function(index, entry) { - apiGroups[entry.group] = 1; - apiGroupTitles[entry.group] = entry.groupTitle || entry.group; - apiVersions[entry.version] = 1; - }); - - // sort groups - apiGroups = Object.keys(apiGroups); - apiGroups.sort(); - - // custom order - if (apiProject.order) - apiGroups = sortByOrder(apiGroups, apiProject.order); - - // sort versions DESC - apiVersions = Object.keys(apiVersions); - apiVersions.sort(semver.compare); - apiVersions.reverse(); - - // - // create Navigationlist - // - var nav = []; - apiGroups.forEach(function(group) { - // Mainmenu entry - nav.push({ - group: group, - isHeader: true, - title: apiGroupTitles[group] - }); - - // Submenu - var oldName = ''; - api.forEach(function(entry) { - if (entry.group === group) { - if (oldName !== entry.name) { - nav.push({ - title: entry.title, - group: group, - name: entry.name, - type: entry.type, - version: entry.version - }); - } else { - nav.push({ - title: entry.title, - group: group, - hidden: true, - name: entry.name, - type: entry.type, - version: entry.version - }); - } - oldName = entry.name; - } - }); - }); - - /** - * Add navigation items by analyzing the HTML content and searching for h1 and h2 tags - * @param nav Object the navigation array - * @param content string the compiled HTML content - * @param index where to insert items - * @return boolean true if any good-looking (i.e. with a group identifier)

tag was found - */ - function add_nav(nav, content, index) { - var found_level1 = false; - if ( ! content) { - return found_level1; - } - var topics = content.match(/(.+?)<\/h(1|2)>/gi); - if ( topics ) { - topics.forEach(function(entry) { - var level = entry.substring(2,3); - var title = entry.replace(/<.+?>/g, ''); // Remove all HTML tags for the title - var entry_tags = entry.match(/id="api-([^\-]+)(?:-(.+))?"/); // Find the group and name in the id property - var group = (entry_tags ? entry_tags[1] : null); - var name = (entry_tags ? entry_tags[2] : null); - if (level==1 && title && group) { - nav.splice(index, 0, { - group: group, - isHeader: true, - title: title, - isFixed: true - }); - index++; - found_level1 = true; - } - if (level==2 && title && group && name) { - nav.splice(index, 0, { - group: group, - name: name, - isHeader: false, - title: title, - isFixed: false, - version: '1.0' - }); - index++; - } - }); - } - return found_level1; - } - - // Mainmenu Header entry - if (apiProject.header) { - var found_level1 = add_nav(nav, apiProject.header.content, 0); // Add level 1 and 2 titles - if (!found_level1) { // If no Level 1 tags were found, make a title - nav.unshift({ - group: '_', - isHeader: true, - title: (apiProject.header.title == null) ? locale.__('General') : apiProject.header.title, - isFixed: true - }); - } - } - - // Mainmenu Footer entry - if (apiProject.footer) { - var last_nav_index = nav.length; - var found_level1 = add_nav(nav, apiProject.footer.content, nav.length); // Add level 1 and 2 titles - if (!found_level1 && apiProject.footer.title != null) { // If no Level 1 tags were found, make a title - nav.splice(last_nav_index, 0, { - group: '_footer', - isHeader: true, - title: apiProject.footer.title, - isFixed: true - }); - } - } - - // render pagetitle - var title = apiProject.title ? apiProject.title : 'apiDoc: ' + apiProject.name + ' - ' + apiProject.version; - $(document).attr('title', title); - - // remove loader - $('#loader').remove(); - - // render sidenav - var fields = { - nav: nav - }; - $('#sidenav').append( templateSidenav(fields) ); - - // render Generator - $('#generator').append( templateGenerator(apiProject) ); - - // render Project - _.extend(apiProject, { versions: apiVersions}); - $('#project').append( templateProject(apiProject) ); - - // render apiDoc, header/footer documentation - if (apiProject.header) - $('#header').append( templateHeader(apiProject.header) ); - - if (apiProject.footer) - $('#footer').append( templateFooter(apiProject.footer) ); - - // - // Render Sections and Articles - // - var articleVersions = {}; - var content = ''; - apiGroups.forEach(function(groupEntry) { - var articles = []; - var oldName = ''; - var fields = {}; - var title = groupEntry; - var description = ''; - articleVersions[groupEntry] = {}; - - // render all articles of a group - api.forEach(function(entry) { - if(groupEntry === entry.group) { - if (oldName !== entry.name) { - // determine versions - api.forEach(function(versionEntry) { - if (groupEntry === versionEntry.group && entry.name === versionEntry.name) { - if ( ! articleVersions[entry.group].hasOwnProperty(entry.name) ) { - articleVersions[entry.group][entry.name] = []; - } - articleVersions[entry.group][entry.name].push(versionEntry.version); - } - }); - fields = { - article: entry, - versions: articleVersions[entry.group][entry.name] - }; - } else { - fields = { - article: entry, - hidden: true, - versions: articleVersions[entry.group][entry.name] - }; - } - - // add prefix URL for endpoint - if (apiProject.url) - fields.article.url = apiProject.url + fields.article.url; - - addArticleSettings(fields, entry); - - if (entry.groupTitle) - title = entry.groupTitle; - - // TODO: make groupDescription compareable with older versions (not important for the moment) - if (entry.groupDescription) - description = entry.groupDescription; - - articles.push({ - article: templateArticle(fields), - group: entry.group, - name: entry.name - }); - oldName = entry.name; - } - }); - - // render Section with Articles - var fields = { - group: groupEntry, - title: title, - description: description, - articles: articles - }; - content += templateSections(fields); - }); - $('#sections').append( content ); - - // Bootstrap Scrollspy - $(this).scrollspy({ target: '#scrollingNav', offset: 18 }); - - // Content-Scroll on Navigation click. - $('.sidenav').find('a').on('click', function(e) { - e.preventDefault(); - var id = $(this).attr('href'); - if ($(id).length > 0) - $('html,body').animate({ scrollTop: parseInt($(id).offset().top) }, 400); - window.location.hash = $(this).attr('href'); - }); - - // Quickjump on Pageload to hash position. - if(window.location.hash) { - var id = window.location.hash; - if ($(id).length > 0) - $('html,body').animate({ scrollTop: parseInt($(id).offset().top) }, 0); - } - - /** - * Check if Parameter (sub) List has a type Field. - * Example: @apiSuccess varname1 No type. - * @apiSuccess {String} varname2 With type. - * - * @param {Object} fields - */ - function _hasTypeInFields(fields) { - var result = false; - $.each(fields, function(name) { - result = result || _.some(fields[name], function(item) { return item.type; }); - }); - return result; - } - - /** - * On Template changes, recall plugins. - */ - function initDynamic() { - // Bootstrap popover - $('button[data-toggle="popover"]').popover().click(function(e) { - e.preventDefault(); - }); - - var version = $('#version strong').html(); - $('#sidenav li').removeClass('is-new'); - if (apiProject.template.withCompare) { - $('#sidenav li[data-version=\'' + version + '\']').each(function(){ - var group = $(this).data('group'); - var name = $(this).data('name'); - var length = $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\']').length; - var index = $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\']').index($(this)); - if (length === 1 || index === (length - 1)) - $(this).addClass('is-new'); - }); - } - - // tabs - $('.nav-tabs-examples a').click(function (e) { - e.preventDefault(); - $(this).tab('show'); - }); - $('.nav-tabs-examples').find('a:first').tab('show'); - - // sample request switch - $('.sample-request-switch').click(function (e) { - var name = '.' + $(this).attr('name') + '-fields'; - $(name).addClass('hide'); - $(this).parent().next(name).removeClass('hide'); - }); - - // call scrollspy refresh method - $(window).scrollspy('refresh'); - - // init modules - sampleRequest.initDynamic(); - } - initDynamic(); - - // Pre- / Code-Format - prettyPrint(); - - // - // HTML-Template specific jQuery-Functions - // - // Change Main Version - $('#versions li.version a').on('click', function(e) { - e.preventDefault(); - - var selectedVersion = $(this).html(); - $('#version strong').html(selectedVersion); - - // hide all - $('article').addClass('hide'); - $('#sidenav li:not(.nav-fixed)').addClass('hide'); - - // show 1st equal or lower Version of each entry - $('article[data-version]').each(function(index) { - var group = $(this).data('group'); - var name = $(this).data('name'); - var version = $(this).data('version'); - - if (semver.lte(version, selectedVersion)) { - if ($('article[data-group=\'' + group + '\'][data-name=\'' + name + '\']:visible').length === 0) { - // enable Article - $('article[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + version + '\']').removeClass('hide'); - // enable Navigation - $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + version + '\']').removeClass('hide'); - $('#sidenav li.nav-header[data-group=\'' + group + '\']').removeClass('hide'); - } - } - }); - - // show 1st equal or lower Version of each entry - $('article[data-version]').each(function(index) { - var group = $(this).data('group'); - $('section#api-' + group).removeClass('hide'); - if ($('section#api-' + group + ' article:visible').length === 0) { - $('section#api-' + group).addClass('hide'); - } else { - $('section#api-' + group).removeClass('hide'); - } - }); - - initDynamic(); - return; - }); - - // compare all article with their predecessor - $('#compareAllWithPredecessor').on('click', changeAllVersionCompareTo); - - // change version of an article - $('article .versions li.version a').on('click', changeVersionCompareTo); - - // compare url-parameter - $.urlParam = function(name) { - var results = new RegExp('[\\?&]' + name + '=([^&#]*)').exec(window.location.href); - return (results && results[1]) ? results[1] : null; - }; - - if ($.urlParam('compare')) { - // URL Paramter ?compare=1 is set - $('#compareAllWithPredecessor').trigger('click'); - - if (window.location.hash) { - var id = window.location.hash; - $('html,body').animate({ scrollTop: parseInt($(id).offset().top) - 18 }, 0); - } - } - - /** - * Initialize search - */ - var options = { - valueNames: [ 'nav-list-item' ] - }; - var endpointsList = new List('scrollingNav', options); - - /** - * Set initial focus to search input - */ - $('#scrollingNav .sidenav-search input.search').focus(); - - /** - * Detect ESC key to reset search - */ - $(document).keyup(function(e) { - if (e.keyCode === 27) $('span.search-reset').click(); - }); - - /** - * Search reset - */ - $('span.search-reset').on('click', function() { - $('#scrollingNav .sidenav-search input.search') - .val("") - .focus() - ; - endpointsList.search(); - }); - - /** - * Change version of an article to compare it to an other version. - */ - function changeVersionCompareTo(e) { - e.preventDefault(); - - var $root = $(this).parents('article'); - var selectedVersion = $(this).html(); - var $button = $root.find('.version'); - var currentVersion = $button.find('strong').html(); - $button.find('strong').html(selectedVersion); - - var group = $root.data('group'); - var name = $root.data('name'); - var version = $root.data('version'); - - var compareVersion = $root.data('compare-version'); - - if (compareVersion === selectedVersion) - return; - - if ( ! compareVersion && version == selectedVersion) - return; - - if (compareVersion && articleVersions[group][name][0] === selectedVersion || version === selectedVersion) { - // the version of the entry is set to the highest version (reset) - resetArticle(group, name, version); - } else { - var $compareToArticle = $('article[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + selectedVersion + '\']'); - - var sourceEntry = {}; - var compareEntry = {}; - $.each(apiByGroupAndName[group][name], function(index, entry) { - if (entry.version === version) - sourceEntry = entry; - if (entry.version === selectedVersion) - compareEntry = entry; - }); - - var fields = { - article: sourceEntry, - compare: compareEntry, - versions: articleVersions[group][name] - }; - - // add unique id - // TODO: replace all group-name-version in template with id. - fields.article.id = fields.article.group + '-' + fields.article.name + '-' + fields.article.version; - fields.article.id = fields.article.id.replace(/\./g, '_'); - - fields.compare.id = fields.compare.group + '-' + fields.compare.name + '-' + fields.compare.version; - fields.compare.id = fields.compare.id.replace(/\./g, '_'); - - var entry = sourceEntry; - if (entry.parameter && entry.parameter.fields) - fields._hasTypeInParameterFields = _hasTypeInFields(entry.parameter.fields); - - if (entry.error && entry.error.fields) - fields._hasTypeInErrorFields = _hasTypeInFields(entry.error.fields); - - if (entry.success && entry.success.fields) - fields._hasTypeInSuccessFields = _hasTypeInFields(entry.success.fields); - - if (entry.info && entry.info.fields) - fields._hasTypeInInfoFields = _hasTypeInFields(entry.info.fields); - - var entry = compareEntry; - if (fields._hasTypeInParameterFields !== true && entry.parameter && entry.parameter.fields) - fields._hasTypeInParameterFields = _hasTypeInFields(entry.parameter.fields); - - if (fields._hasTypeInErrorFields !== true && entry.error && entry.error.fields) - fields._hasTypeInErrorFields = _hasTypeInFields(entry.error.fields); - - if (fields._hasTypeInSuccessFields !== true && entry.success && entry.success.fields) - fields._hasTypeInSuccessFields = _hasTypeInFields(entry.success.fields); - - if (fields._hasTypeInInfoFields !== true && entry.info && entry.info.fields) - fields._hasTypeInInfoFields = _hasTypeInFields(entry.info.fields); - - var content = templateCompareArticle(fields); - $root.after(content); - var $content = $root.next(); - - // Event on.click re-assign - $content.find('.versions li.version a').on('click', changeVersionCompareTo); - - // select navigation - $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + currentVersion + '\']').addClass('has-modifications'); - - $root.remove(); - // TODO: on change main version or select the highest version re-render - } - - initDynamic(); - } - - /** - * Compare all currently selected Versions with their predecessor. - */ - function changeAllVersionCompareTo(e) { - e.preventDefault(); - $('article:visible .versions').each(function(){ - var $root = $(this).parents('article'); - var currentVersion = $root.data('version'); - var $foundElement = null; - $(this).find('li.version a').each(function() { - var selectVersion = $(this).html(); - if (selectVersion < currentVersion && ! $foundElement) - $foundElement = $(this); - }); - - if($foundElement) - $foundElement.trigger('click'); - }); - initDynamic(); - } - - /** - * Sort the fields. - */ - function sortFields(fields_object) { - $.each(fields_object, function (key, fields) { - - var reversed = fields.slice().reverse() - - var max_dot_count = Math.max.apply(null, reversed.map(function (item) { - return item.field.split(".").length - 1; - })) - - for (var dot_count = 1; dot_count <= max_dot_count; dot_count++) { - reversed.forEach(function (item, index) { - var parts = item.field.split("."); - if (parts.length - 1 == dot_count) { - var fields_names = fields.map(function (item) { return item.field; }); - if (parts.slice(1).length >= 1) { - var prefix = parts.slice(0, parts.length - 1).join("."); - var prefix_index = fields_names.indexOf(prefix); - if (prefix_index > -1) { - fields.splice(fields_names.indexOf(item.field), 1); - fields.splice(prefix_index + 1, 0, item); - } - } - } - }); - } - }); - } - - /** - * Add article settings. - */ - function addArticleSettings(fields, entry) { - // add unique id - // TODO: replace all group-name-version in template with id. - fields.id = fields.article.group + '-' + fields.article.name + '-' + fields.article.version; - fields.id = fields.id.replace(/\./g, '_'); - - if (entry.header && entry.header.fields) { - sortFields(entry.header.fields); - fields._hasTypeInHeaderFields = _hasTypeInFields(entry.header.fields); - } - - if (entry.parameter && entry.parameter.fields) { - sortFields(entry.parameter.fields); - fields._hasTypeInParameterFields = _hasTypeInFields(entry.parameter.fields); - } - - if (entry.error && entry.error.fields) { - sortFields(entry.error.fields); - fields._hasTypeInErrorFields = _hasTypeInFields(entry.error.fields); - } - - if (entry.success && entry.success.fields) { - sortFields(entry.success.fields); - fields._hasTypeInSuccessFields = _hasTypeInFields(entry.success.fields); - } - - if (entry.info && entry.info.fields) { - sortFields(entry.info.fields); - fields._hasTypeInInfoFields = _hasTypeInFields(entry.info.fields); - } - - // add template settings - fields.template = apiProject.template; - } - - /** - * Render Article. - */ - function renderArticle(group, name, version) { - var entry = {}; - $.each(apiByGroupAndName[group][name], function(index, currentEntry) { - if (currentEntry.version === version) - entry = currentEntry; - }); - var fields = { - article: entry, - versions: articleVersions[group][name] - }; - - addArticleSettings(fields, entry); - - return templateArticle(fields); - } - - /** - * Render original Article and remove the current visible Article. - */ - function resetArticle(group, name, version) { - var $root = $('article[data-group=\'' + group + '\'][data-name=\'' + name + '\']:visible'); - var content = renderArticle(group, name, version); - - $root.after(content); - var $content = $root.next(); - - // Event on.click muss neu zugewiesen werden (sollte eigentlich mit on automatisch funktionieren... sollte) - $content.find('.versions li.version a').on('click', changeVersionCompareTo); - - $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + version + '\']').removeClass('has-modifications'); - - $root.remove(); - return; - } - - /** - * Load google fonts. - */ - function loadGoogleFontCss() { - WebFont.load({ - active: function() { - // Update scrollspy - $(window).scrollspy('refresh') - }, - google: { - families: ['Source Code Pro', 'Source Sans Pro:n4,n6,n7'] - } - }); - } - - /** - * Return ordered entries by custom order and append not defined entries to the end. - * @param {String[]} elements - * @param {String[]} order - * @param {String} splitBy - * @return {String[]} Custom ordered list. - */ - function sortByOrder(elements, order, splitBy) { - var results = []; - order.forEach (function(name) { - if (splitBy) - elements.forEach (function(element) { - var parts = element.split(splitBy); - var key = parts[1]; // reference keep for sorting - if (key == name) - results.push(element); - }); - else - elements.forEach (function(key) { - if (key == name) - results.push(name); - }); - }); - // Append all other entries that ar not defined in order - elements.forEach(function(element) { - if (results.indexOf(element) === -1) - results.push(element); - }); - return results; - } - -}); diff --git a/doc/utils/handlebars_helper.js b/doc/utils/handlebars_helper.js deleted file mode 100644 index a5d5c4fdc..000000000 --- a/doc/utils/handlebars_helper.js +++ /dev/null @@ -1,357 +0,0 @@ -define([ - 'locales', - 'handlebars', - 'diffMatchPatch' -], function(locale, Handlebars, DiffMatchPatch) { - - /** - * Return a text as markdown. - * Currently only a little helper to replace apidoc-inline Links (#Group:Name). - * Should be replaced with a full markdown lib. - * @param string text - */ - Handlebars.registerHelper('markdown', function(text) { - if ( ! text ) { - return text; - } - text = text.replace(/((\[(.*?)\])?\(#)((.+?):(.+?))(\))/mg, function(match, p1, p2, p3, p4, p5, p6) { - var link = p3 || p5 + '/' + p6; - return '' + link + ''; - }); - return text; - }); - - /** - * start/stop timer for simple performance check. - */ - var timer; - Handlebars.registerHelper('startTimer', function(text) { - timer = new Date(); - return ''; - }); - - Handlebars.registerHelper('stopTimer', function(text) { - console.log(new Date() - timer); - return ''; - }); - - /** - * Return localized Text. - * @param string text - */ - Handlebars.registerHelper('__', function(text) { - return locale.__(text); - }); - - /** - * Console log. - * @param mixed obj - */ - Handlebars.registerHelper('cl', function(obj) { - console.log(obj); - return ''; - }); - - /** - * Replace underscore with space. - * @param string text - */ - Handlebars.registerHelper('underscoreToSpace', function(text) { - return text.replace(/(_+)/g, ' '); - }); - - /** - * - */ - Handlebars.registerHelper('assign', function(name) { - if(arguments.length > 0) { - var type = typeof(arguments[1]); - var arg = null; - if(type === 'string' || type === 'number' || type === 'boolean') arg = arguments[1]; - Handlebars.registerHelper(name, function() { return arg; }); - } - return ''; - }); - - /** - * - */ - Handlebars.registerHelper('nl2br', function(text) { - return _handlebarsNewlineToBreak(text); - }); - - /** - * - */ - Handlebars.registerHelper('if_eq', function(context, options) { - var compare = context; - // Get length if context is an object - if (context instanceof Object && ! (options.hash.compare instanceof Object)) - compare = Object.keys(context).length; - - if (compare === options.hash.compare) - return options.fn(this); - - return options.inverse(this); - }); - - /** - * - */ - Handlebars.registerHelper('if_gt', function(context, options) { - var compare = context; - // Get length if context is an object - if (context instanceof Object && ! (options.hash.compare instanceof Object)) - compare = Object.keys(context).length; - - if(compare > options.hash.compare) - return options.fn(this); - - return options.inverse(this); - }); - - /** - * - */ - var templateCache = {}; - Handlebars.registerHelper('subTemplate', function(name, sourceContext) { - if ( ! templateCache[name]) - templateCache[name] = Handlebars.compile($('#template-' + name).html()); - - var template = templateCache[name]; - var templateContext = $.extend({}, this, sourceContext.hash); - return new Handlebars.SafeString( template(templateContext) ); - }); - - /** - * - */ - Handlebars.registerHelper('toLowerCase', function(value) { - return (value && typeof value === 'string') ? value.toLowerCase() : ''; - }); - - /** - * - */ - Handlebars.registerHelper('splitFill', function(value, splitChar, fillChar) { - var splits = value.split(splitChar); - return new Array(splits.length).join(fillChar) + splits[splits.length - 1]; - }); - - /** - * Convert Newline to HTML-Break (nl2br). - * - * @param {String} text - * @returns {String} - */ - function _handlebarsNewlineToBreak(text) { - return ('' + text).replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + '
' + '$2'); - } - - /** - * - */ - Handlebars.registerHelper('each_compare_list_field', function(source, compare, options) { - var fieldName = options.hash.field; - var newSource = []; - if (source) { - source.forEach(function(entry) { - var values = entry; - values['key'] = entry[fieldName]; - newSource.push(values); - }); - } - - var newCompare = []; - if (compare) { - compare.forEach(function(entry) { - var values = entry; - values['key'] = entry[fieldName]; - newCompare.push(values); - }); - } - return _handlebarsEachCompared('key', newSource, newCompare, options); - }); - - /** - * - */ - Handlebars.registerHelper('each_compare_keys', function(source, compare, options) { - var newSource = []; - if (source) { - var sourceFields = Object.keys(source); - sourceFields.forEach(function(name) { - var values = {}; - values['value'] = source[name]; - values['key'] = name; - newSource.push(values); - }); - } - - var newCompare = []; - if (compare) { - var compareFields = Object.keys(compare); - compareFields.forEach(function(name) { - var values = {}; - values['value'] = compare[name]; - values['key'] = name; - newCompare.push(values); - }); - } - return _handlebarsEachCompared('key', newSource, newCompare, options); - }); - - /** - * - */ - Handlebars.registerHelper('each_compare_field', function(source, compare, options) { - return _handlebarsEachCompared('field', source, compare, options); - }); - - /** - * - */ - Handlebars.registerHelper('each_compare_title', function(source, compare, options) { - return _handlebarsEachCompared('title', source, compare, options); - }); - - /** - * - */ - Handlebars.registerHelper('reformat', function(source, type){ - if (type == 'json') - try { - return JSON.stringify(JSON.parse(source.trim()),null, " "); - } catch(e) { - - } - return source - }); - - /** - * - */ - Handlebars.registerHelper('showDiff', function(source, compare, options) { - var ds = ''; - if(source === compare) { - ds = source; - } else { - if( ! source) - return compare; - - if( ! compare) - return source; - - var d = diffMatchPatch.diff_main(compare, source); - diffMatchPatch.diff_cleanupSemantic(d); - ds = diffMatchPatch.diff_prettyHtml(d); - ds = ds.replace(/¶/gm, ''); - } - if(options === 'nl2br') - ds = _handlebarsNewlineToBreak(ds); - - return ds; - }); - - /** - * - */ - function _handlebarsEachCompared(fieldname, source, compare, options) - { - var dataList = []; - var index = 0; - if(source) { - source.forEach(function(sourceEntry) { - var found = false; - if (compare) { - compare.forEach(function(compareEntry) { - if(sourceEntry[fieldname] === compareEntry[fieldname]) { - var data = { - typeSame: true, - source: sourceEntry, - compare: compareEntry, - index: index - }; - dataList.push(data); - found = true; - index++; - } - }); - } - if ( ! found) { - var data = { - typeIns: true, - source: sourceEntry, - index: index - }; - dataList.push(data); - index++; - } - }); - } - - if (compare) { - compare.forEach(function(compareEntry) { - var found = false; - if (source) { - source.forEach(function(sourceEntry) { - if(sourceEntry[fieldname] === compareEntry[fieldname]) - found = true; - }); - } - if ( ! found) { - var data = { - typeDel: true, - compare: compareEntry, - index: index - }; - dataList.push(data); - index++; - } - }); - } - - var ret = ''; - var length = dataList.length; - for (var index in dataList) { - if(index == (length - 1)) - dataList[index]['_last'] = true; - ret = ret + options.fn(dataList[index]); - } - return ret; - } - - var diffMatchPatch = new DiffMatchPatch(); - - /** - * Overwrite Colors - */ - DiffMatchPatch.prototype.diff_prettyHtml = function(diffs) { - var html = []; - var pattern_amp = /&/g; - var pattern_lt = //g; - var pattern_para = /\n/g; - for (var x = 0; x < diffs.length; x++) { - var op = diffs[x][0]; // Operation (insert, delete, equal) - var data = diffs[x][1]; // Text of change. - var text = data.replace(pattern_amp, '&').replace(pattern_lt, '<') - .replace(pattern_gt, '>').replace(pattern_para, '¶
'); - switch (op) { - case DIFF_INSERT: - html[x] = '' + text + ''; - break; - case DIFF_DELETE: - html[x] = '' + text + ''; - break; - case DIFF_EQUAL: - html[x] = '' + text + ''; - break; - } - } - return html.join(''); - }; - - // Exports - return Handlebars; -}); diff --git a/doc/utils/send_sample_request.js b/doc/utils/send_sample_request.js deleted file mode 100755 index f2396ea92..000000000 --- a/doc/utils/send_sample_request.js +++ /dev/null @@ -1,184 +0,0 @@ -define([ - 'jquery', - 'lodash' -], function($, _) { - - var initDynamic = function() { - // Button send - $(".sample-request-send").off("click"); - $(".sample-request-send").on("click", function(e) { - e.preventDefault(); - var $root = $(this).parents("article"); - var group = $root.data("group"); - var name = $root.data("name"); - var version = $root.data("version"); - sendSampleRequest(group, name, version, $(this).data("sample-request-type")); - }); - - // Button clear - $(".sample-request-clear").off("click"); - $(".sample-request-clear").on("click", function(e) { - e.preventDefault(); - var $root = $(this).parents("article"); - var group = $root.data("group"); - var name = $root.data("name"); - var version = $root.data("version"); - clearSampleRequest(group, name, version); - }); - }; // initDynamic - - function sendSampleRequest(group, name, version, type) - { - var $root = $('article[data-group="' + group + '"][data-name="' + name + '"][data-version="' + version + '"]'); - - // Optional header - var header = {}; - $root.find(".sample-request-header:checked").each(function(i, element) { - var group = $(element).data("sample-request-header-group-id"); - $root.find("[data-sample-request-header-group=\"" + group + "\"]").each(function(i, element) { - var key = $(element).data("sample-request-header-name"); - var value = element.value; - if ( ! element.optional && element.defaultValue !== '') { - value = element.defaultValue; - } - header[key] = value; - }); - }); - - // create JSON dictionary of parameters - var param = {}; - var paramType = {}; - $root.find(".sample-request-param:checked").each(function(i, element) { - var group = $(element).data("sample-request-param-group-id"); - $root.find("[data-sample-request-param-group=\"" + group + "\"]").not(function(){ - return $(this).val() == "" && $(this).is("[data-sample-request-param-optional='true']"); - }).each(function(i, element) { - var key = $(element).data("sample-request-param-name"); - var value = element.value; - if ( ! element.optional && element.defaultValue !== '') { - value = element.defaultValue; - } - param[key] = value; - paramType[key] = $(element).next().text(); - }); - }); - - // grab user-inputted URL - var url = $root.find(".sample-request-url").val(); - - // Insert url parameter - var pattern = pathToRegexp(url, null); - var matches = pattern.exec(url); - for (var i = 1; i < matches.length; i++) { - var key = matches[i].substr(1); - if (param[key] !== undefined) { - url = url.replace(matches[i], encodeURIComponent(param[key])); - - // remove URL parameters from list - delete param[key]; - } - } // for - - $root.find(".sample-request-response").fadeTo(250, 1); - $root.find(".sample-request-response-json").html("Loading..."); - refreshScrollSpy(); - - _.each( param, function( val, key ) { - var t = paramType[ key ].toLowerCase(); - if ( t === 'object' || t === 'array' ) { - try { - param[ key ] = JSON.parse( val ); - } catch (e) { - } - } - }); - - // send AJAX request, catch success or error callback - var ajaxRequest = { - url : url, - headers : header, - data : param, - type : type.toUpperCase(), - success : displaySuccess, - error : displayError - }; - - $.ajax(ajaxRequest); - - - function displaySuccess(data, status, jqXHR) { - var jsonResponse; - try { - jsonResponse = JSON.parse(jqXHR.responseText); - jsonResponse = JSON.stringify(jsonResponse, null, 4); - } catch (e) { - jsonResponse = data; - } - $root.find(".sample-request-response-json").html(jsonResponse); - refreshScrollSpy(); - }; - - function displayError(jqXHR, textStatus, error) { - var message = "Error " + jqXHR.status + ": " + error; - var jsonResponse; - try { - jsonResponse = JSON.parse(jqXHR.responseText); - jsonResponse = JSON.stringify(jsonResponse, null, 4); - } catch (e) { - jsonResponse = escape(jqXHR.responseText); - } - - if (jsonResponse) - message += "
" + jsonResponse; - - // flicker on previous error to make clear that there is a new response - if($root.find(".sample-request-response").is(":visible")) - $root.find(".sample-request-response").fadeTo(1, 0.1); - - $root.find(".sample-request-response").fadeTo(250, 1); - $root.find(".sample-request-response-json").html(message); - refreshScrollSpy(); - }; - } - - function clearSampleRequest(group, name, version) - { - var $root = $('article[data-group="' + group + '"][data-name="' + name + '"][data-version="' + version + '"]'); - - // hide sample response - $root.find(".sample-request-response-json").html(""); - $root.find(".sample-request-response").hide(); - - // reset value of parameters - $root.find(".sample-request-param").each(function(i, element) { - element.value = ""; - }); - - // restore default URL - var $urlElement = $root.find(".sample-request-url"); - $urlElement.val($urlElement.prop("defaultValue")); - - refreshScrollSpy(); - } - - function refreshScrollSpy() - { - $('[data-spy="scroll"]').each(function () { - $(this).scrollspy("refresh"); - }); - } - - function escapeHtml(str) { - var div = document.createElement("div"); - div.appendChild(document.createTextNode(str)); - return div.innerHTML; - } - - /** - * Exports. - */ - return { - initDynamic: initDynamic - }; - -}); diff --git a/doc/vendor/bootstrap.min.css b/doc/vendor/bootstrap.min.css deleted file mode 100644 index ed3905e0e..000000000 --- a/doc/vendor/bootstrap.min.css +++ /dev/null @@ -1,6 +0,0 @@ -/*! - * Bootstrap v3.3.7 (http://getbootstrap.com) - * Copyright 2011-2016 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} -/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/doc/vendor/bootstrap.min.js b/doc/vendor/bootstrap.min.js deleted file mode 100644 index 9bcd2fcca..000000000 --- a/doc/vendor/bootstrap.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v3.3.7 (http://getbootstrap.com) - * Copyright 2011-2016 Twitter, Inc. - * Licensed under the MIT license - */ -if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){if(a(b.target).is(this))return b.handleObj.handler.apply(this,arguments)}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.7",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a("#"===f?[]:f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.7",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c).prop(c,!0)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c).prop(c,!1))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target).closest(".btn");b.call(d,"toggle"),a(c.target).is('input[type="radio"], input[type="checkbox"]')||(c.preventDefault(),d.is("input,button")?d.trigger("focus"):d.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(a>this.$items.length-1||a<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.7",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.7",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);if(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),!c.isInStateTrue())return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null,a.$element=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.7",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.7",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file diff --git a/doc/vendor/diff_match_patch.min.js b/doc/vendor/diff_match_patch.min.js deleted file mode 100644 index c41b51327..000000000 --- a/doc/vendor/diff_match_patch.min.js +++ /dev/null @@ -1,49 +0,0 @@ -(function(){function diff_match_patch(){this.Diff_Timeout=1;this.Diff_EditCost=4;this.Match_Threshold=0.5;this.Match_Distance=1E3;this.Patch_DeleteThreshold=0.5;this.Patch_Margin=4;this.Match_MaxBits=32} -diff_match_patch.prototype.diff_main=function(a,b,c,d){"undefined"==typeof d&&(d=0>=this.Diff_Timeout?Number.MAX_VALUE:(new Date).getTime()+1E3*this.Diff_Timeout);if(null==a||null==b)throw Error("Null input. (diff_main)");if(a==b)return a?[[0,a]]:[];"undefined"==typeof c&&(c=!0);var e=c,f=this.diff_commonPrefix(a,b);c=a.substring(0,f);a=a.substring(f);b=b.substring(f);var f=this.diff_commonSuffix(a,b),g=a.substring(a.length-f);a=a.substring(0,a.length-f);b=b.substring(0,b.length-f);a=this.diff_compute_(a, -b,e,d);c&&a.unshift([0,c]);g&&a.push([0,g]);this.diff_cleanupMerge(a);return a}; -diff_match_patch.prototype.diff_compute_=function(a,b,c,d){if(!a)return[[1,b]];if(!b)return[[-1,a]];var e=a.length>b.length?a:b,f=a.length>b.length?b:a,g=e.indexOf(f);return-1!=g?(c=[[1,e.substring(0,g)],[0,f],[1,e.substring(g+f.length)]],a.length>b.length&&(c[0][0]=c[2][0]=-1),c):1==f.length?[[-1,a],[1,b]]:(e=this.diff_halfMatch_(a,b))?(f=e[0],a=e[1],g=e[2],b=e[3],e=e[4],f=this.diff_main(f,g,c,d),c=this.diff_main(a,b,c,d),f.concat([[0,e]],c)):c&&100c);v++){for(var n=-v+r;n<=v-t;n+=2){var l=g+n,m;m=n==-v||n!=v&&j[l-1]d)t+=2;else if(s>e)r+=2;else if(q&&(l=g+k-n,0<=l&&l= -u)return this.diff_bisectSplit_(a,b,m,s,c)}}for(n=-v+p;n<=v-w;n+=2){l=g+n;u=n==-v||n!=v&&i[l-1]d)w+=2;else if(m>e)p+=2;else if(!q&&(l=g+k-n,0<=l&&(l=u)))return this.diff_bisectSplit_(a,b,m,s,c)}}return[[-1,a],[1,b]]}; -diff_match_patch.prototype.diff_bisectSplit_=function(a,b,c,d,e){var f=a.substring(0,c),g=b.substring(0,d);a=a.substring(c);b=b.substring(d);f=this.diff_main(f,g,!1,e);e=this.diff_main(a,b,!1,e);return f.concat(e)}; -diff_match_patch.prototype.diff_linesToChars_=function(a,b){function c(a){for(var b="",c=0,f=-1,g=d.length;fd?a=a.substring(c-d):c=a.length?[h,j,n,l,g]:null}if(0>=this.Diff_Timeout)return null; -var d=a.length>b.length?a:b,e=a.length>b.length?b:a;if(4>d.length||2*e.lengthd[4].length?g:d:d:g;var j;a.length>b.length?(g=h[0],d=h[1],e=h[2],j=h[3]):(e=h[0],j=h[1],g=h[2],d=h[3]);h=h[4];return[g,d,e,j,h]}; -diff_match_patch.prototype.diff_cleanupSemantic=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=0,h=0,j=0,i=0;f=e){if(d>=b.length/2||d>=c.length/2)a.splice(f,0,[0,c.substring(0,d)]),a[f-1][1]=b.substring(0,b.length-d),a[f+1][1]=c.substring(d),f++}else if(e>=b.length/2||e>=c.length/2)a.splice(f,0,[0,b.substring(0,e)]),a[f-1][0]=1,a[f-1][1]=c.substring(0,c.length-e),a[f+1][0]=-1,a[f+1][1]=b.substring(e),f++;f++}f++}}; -diff_match_patch.prototype.diff_cleanupSemanticLossless=function(a){function b(a,b){if(!a||!b)return 6;var c=a.charAt(a.length-1),d=b.charAt(0),e=c.match(diff_match_patch.nonAlphaNumericRegex_),f=d.match(diff_match_patch.nonAlphaNumericRegex_),g=e&&c.match(diff_match_patch.whitespaceRegex_),h=f&&d.match(diff_match_patch.whitespaceRegex_),c=g&&c.match(diff_match_patch.linebreakRegex_),d=h&&d.match(diff_match_patch.linebreakRegex_),i=c&&a.match(diff_match_patch.blanklineEndRegex_),j=d&&b.match(diff_match_patch.blanklineStartRegex_); -return i||j?5:c||d?4:e&&!g&&h?3:g||h?2:e||f?1:0}for(var c=1;c=i&&(i=k,g=d,h=e,j=f)}a[c-1][1]!=g&&(g?a[c-1][1]=g:(a.splice(c-1,1),c--),a[c][1]= -h,j?a[c+1][1]=j:(a.splice(c+1,1),c--))}c++}};diff_match_patch.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/;diff_match_patch.whitespaceRegex_=/\s/;diff_match_patch.linebreakRegex_=/[\r\n]/;diff_match_patch.blanklineEndRegex_=/\n\r?\n$/;diff_match_patch.blanklineStartRegex_=/^\r?\n\r?\n/; -diff_match_patch.prototype.diff_cleanupEfficiency=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=!1,h=!1,j=!1,i=!1;fb)break;e=c;f=d}return a.length!=g&&-1===a[g][0]?f:f+(b-e)}; -diff_match_patch.prototype.diff_prettyHtml=function(a){for(var b=[],c=/&/g,d=//g,f=/\n/g,g=0;g");switch(h){case 1:b[g]=''+j+"";break;case -1:b[g]=''+j+"";break;case 0:b[g]=""+j+""}}return b.join("")}; -diff_match_patch.prototype.diff_text1=function(a){for(var b=[],c=0;cthis.Match_MaxBits)throw Error("Pattern too long for this browser.");var e=this.match_alphabet_(b),f=this,g=this.Match_Threshold,h=a.indexOf(b,c);-1!=h&&(g=Math.min(d(0,h),g),h=a.lastIndexOf(b,c+b.length),-1!=h&&(g=Math.min(d(0,h),g)));for(var j=1<=i;p--){var w=e[a.charAt(p-1)];k[p]=0===t?(k[p+1]<<1|1)&w:(k[p+1]<<1|1)&w|((r[p+1]|r[p])<<1|1)|r[p+1];if(k[p]&j&&(w=d(t,p-1),w<=g))if(g=w,h=p-1,h>c)i=Math.max(1,2*c-h);else break}if(d(t+1,c)>g)break;r=k}return h}; -diff_match_patch.prototype.match_alphabet_=function(a){for(var b={},c=0;c=2*this.Patch_Margin&& -e&&(this.patch_addContext_(a,h),c.push(a),a=new diff_match_patch.patch_obj,e=0,h=d,f=g)}1!==i&&(f+=k.length);-1!==i&&(g+=k.length)}e&&(this.patch_addContext_(a,h),c.push(a));return c};diff_match_patch.prototype.patch_deepCopy=function(a){for(var b=[],c=0;cthis.Match_MaxBits){if(j=this.match_main(b,h.substring(0,this.Match_MaxBits),g),-1!=j&&(i=this.match_main(b,h.substring(h.length-this.Match_MaxBits),g+h.length-this.Match_MaxBits),-1==i||j>=i))j=-1}else j=this.match_main(b,h,g); -if(-1==j)e[f]=!1,d-=a[f].length2-a[f].length1;else if(e[f]=!0,d=j-g,g=-1==i?b.substring(j,j+h.length):b.substring(j,i+this.Match_MaxBits),h==g)b=b.substring(0,j)+this.diff_text2(a[f].diffs)+b.substring(j+h.length);else if(g=this.diff_main(h,g,!1),h.length>this.Match_MaxBits&&this.diff_levenshtein(g)/h.length>this.Patch_DeleteThreshold)e[f]=!1;else{this.diff_cleanupSemanticLossless(g);for(var h=0,k,i=0;ie[0][1].length){var f=b-e[0][1].length;e[0][1]=c.substring(e[0][1].length)+e[0][1];d.start1-=f;d.start2-=f;d.length1+=f;d.length2+=f}d=a[a.length-1];e=d.diffs;0==e.length||0!=e[e.length-1][0]?(e.push([0, -c]),d.length1+=b,d.length2+=b):b>e[e.length-1][1].length&&(f=b-e[e.length-1][1].length,e[e.length-1][1]+=c.substring(0,f),d.length1+=f,d.length2+=f);return c}; -diff_match_patch.prototype.patch_splitMax=function(a){for(var b=this.Match_MaxBits,c=0;c2*b?(h.length1+=i.length,e+=i.length,j=!1,h.diffs.push([g,i]),d.diffs.shift()):(i=i.substring(0,b-h.length1-this.Patch_Margin),h.length1+=i.length,e+=i.length,0===g?(h.length2+=i.length,f+=i.length):j=!1,h.diffs.push([g,i]),i==d.diffs[0][1]?d.diffs.shift():d.diffs[0][1]=d.diffs[0][1].substring(i.length))}g=this.diff_text2(h.diffs);g=g.substring(g.length-this.Patch_Margin);i=this.diff_text1(d.diffs).substring(0,this.Patch_Margin);""!==i&& -(h.length1+=i.length,h.length2+=i.length,0!==h.diffs.length&&0===h.diffs[h.diffs.length-1][0]?h.diffs[h.diffs.length-1][1]+=i:h.diffs.push([0,i]));j||a.splice(++c,0,h)}}};diff_match_patch.prototype.patch_toText=function(a){for(var b=[],c=0;c= 2.0.0-beta.1",7:">= 4.0.0"};b.REVISION_CHANGES=o;var p="[object Object]";d.prototype={constructor:d,logger:l["default"],log:l["default"].log,registerHelper:function(a,b){if(f.toString.call(a)===p){if(b)throw new h["default"]("Arg not supported with multiple helpers");f.extend(this.helpers,a)}else this.helpers[a]=b},unregisterHelper:function(a){delete this.helpers[a]},registerPartial:function(a,b){if(f.toString.call(a)===p)f.extend(this.partials,a);else{if("undefined"==typeof b)throw new h["default"]('Attempting to register a partial called "'+a+'" as undefined');this.partials[a]=b}},unregisterPartial:function(a){delete this.partials[a]},registerDecorator:function(a,b){if(f.toString.call(a)===p){if(b)throw new h["default"]("Arg not supported with multiple decorators");f.extend(this.decorators,a)}else this.decorators[a]=b},unregisterDecorator:function(a){delete this.decorators[a]}};var q=l["default"].log;b.log=q,b.createFrame=f.createFrame,b.logger=l["default"]},function(a,b){"use strict";function c(a){return k[a]}function d(a){for(var b=1;bc;c++)if(a[c]===b)return c;return-1}function f(a){if("string"!=typeof a){if(a&&a.toHTML)return a.toHTML();if(null==a)return"";if(!a)return a+"";a=""+a}return m.test(a)?a.replace(l,c):a}function g(a){return a||0===a?p(a)&&0===a.length?!0:!1:!0}function h(a){var b=d({},a);return b._parent=a,b}function i(a,b){return a.path=b,a}function j(a,b){return(a?a+".":"")+b}b.__esModule=!0,b.extend=d,b.indexOf=e,b.escapeExpression=f,b.isEmpty=g,b.createFrame=h,b.blockParams=i,b.appendContextPath=j;var k={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`","=":"="},l=/[&<>"'`=]/g,m=/[&<>"'`=]/,n=Object.prototype.toString;b.toString=n;var o=function(a){return"function"==typeof a};o(/x/)&&(b.isFunction=o=function(a){return"function"==typeof a&&"[object Function]"===n.call(a)}),b.isFunction=o;var p=Array.isArray||function(a){return a&&"object"==typeof a?"[object Array]"===n.call(a):!1};b.isArray=p},function(a,b){"use strict";function c(a,b){var e=b&&b.loc,f=void 0,g=void 0;e&&(f=e.start.line,g=e.start.column,a+=" - "+f+":"+g);for(var h=Error.prototype.constructor.call(this,a),i=0;i0?(c.ids&&(c.ids=[c.name]),a.helpers.each(b,c)):e(this);if(c.data&&c.ids){var g=d.createFrame(c.data);g.contextPath=d.appendContextPath(c.data.contextPath,c.name),c={data:g}}return f(b,c)})},a.exports=b["default"]},function(a,b,c){"use strict";var d=c(1)["default"];b.__esModule=!0;var e=c(5),f=c(6),g=d(f);b["default"]=function(a){a.registerHelper("each",function(a,b){function c(b,c,f){j&&(j.key=b,j.index=c,j.first=0===c,j.last=!!f,k&&(j.contextPath=k+b)),i+=d(a[b],{data:j,blockParams:e.blockParams([a[b],b],[k+b,null])})}if(!b)throw new g["default"]("Must pass iterator to #each");var d=b.fn,f=b.inverse,h=0,i="",j=void 0,k=void 0;if(b.data&&b.ids&&(k=e.appendContextPath(b.data.contextPath,b.ids[0])+"."),e.isFunction(a)&&(a=a.call(this)),b.data&&(j=e.createFrame(b.data)),a&&"object"==typeof a)if(e.isArray(a))for(var l=a.length;l>h;h++)h in a&&c(h,h,h===a.length-1);else{var m=void 0;for(var n in a)a.hasOwnProperty(n)&&(void 0!==m&&c(m,h-1),m=n,h++);void 0!==m&&c(m,h-1,!0)}return 0===h&&(i=f(this)),i})},a.exports=b["default"]},function(a,b,c){"use strict";var d=c(1)["default"];b.__esModule=!0;var e=c(6),f=d(e);b["default"]=function(a){a.registerHelper("helperMissing",function(){if(1!==arguments.length)throw new f["default"]('Missing helper: "'+arguments[arguments.length-1].name+'"')})},a.exports=b["default"]},function(a,b,c){"use strict";b.__esModule=!0;var d=c(5);b["default"]=function(a){a.registerHelper("if",function(a,b){return d.isFunction(a)&&(a=a.call(this)),!b.hash.includeZero&&!a||d.isEmpty(a)?b.inverse(this):b.fn(this)}),a.registerHelper("unless",function(b,c){return a.helpers["if"].call(this,b,{fn:c.inverse,inverse:c.fn,hash:c.hash})})},a.exports=b["default"]},function(a,b){"use strict";b.__esModule=!0,b["default"]=function(a){a.registerHelper("log",function(){for(var b=[void 0],c=arguments[arguments.length-1],d=0;d=0?b:parseInt(a,10)}return a},log:function(a){if(a=e.lookupLevel(a),"undefined"!=typeof console&&e.lookupLevel(e.level)<=a){var b=e.methodMap[a];console[b]||(b="log");for(var c=arguments.length,d=Array(c>1?c-1:0),f=1;c>f;f++)d[f-1]=arguments[f];console[b].apply(console,d)}}};b["default"]=e,a.exports=b["default"]},function(a,b){"use strict";function c(a){this.string=a}b.__esModule=!0,c.prototype.toString=c.prototype.toHTML=function(){return""+this.string},b["default"]=c,a.exports=b["default"]},function(a,b,c){"use strict";function d(a){var b=a&&a[0]||1,c=r.COMPILER_REVISION;if(b!==c){if(c>b){var d=r.REVISION_CHANGES[c],e=r.REVISION_CHANGES[b];throw new q["default"]("Template was precompiled with an older version of Handlebars than the current runtime. Please update your precompiler to a newer version ("+d+") or downgrade your runtime to an older version ("+e+").")}throw new q["default"]("Template was precompiled with a newer version of Handlebars than the current runtime. Please update your runtime to a newer version ("+a[1]+").")}}function e(a,b){function c(c,d,e){e.hash&&(d=o.extend({},d,e.hash),e.ids&&(e.ids[0]=!0)),c=b.VM.resolvePartial.call(this,c,d,e);var f=b.VM.invokePartial.call(this,c,d,e);if(null==f&&b.compile&&(e.partials[e.name]=b.compile(c,a.compilerOptions,b),f=e.partials[e.name](d,e)),null!=f){if(e.indent){for(var g=f.split("\n"),h=0,i=g.length;i>h&&(g[h]||h+1!==i);h++)g[h]=e.indent+g[h];f=g.join("\n")}return f}throw new q["default"]("The partial "+e.name+" could not be compiled when running in runtime-only mode")}function d(b){function c(b){return""+a.main(e,b,e.helpers,e.partials,g,i,h)}var f=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],g=f.data;d._setup(f),!f.partial&&a.useData&&(g=j(b,g));var h=void 0,i=a.useBlockParams?[]:void 0;return a.useDepths&&(h=f.depths?b!==f.depths[0]?[b].concat(f.depths):f.depths:[b]),(c=k(a.main,c,e,f.depths||[],g,i))(b,f)}if(!b)throw new q["default"]("No environment passed to template");if(!a||!a.main)throw new q["default"]("Unknown template object: "+typeof a);a.main.decorator=a.main_d,b.VM.checkRevision(a.compiler);var e={strict:function(a,b){if(!(b in a))throw new q["default"]('"'+b+'" not defined in '+a);return a[b]},lookup:function(a,b){for(var c=a.length,d=0;c>d;d++)if(a[d]&&null!=a[d][b])return a[d][b]},lambda:function(a,b){return"function"==typeof a?a.call(b):a},escapeExpression:o.escapeExpression,invokePartial:c,fn:function(b){var c=a[b];return c.decorator=a[b+"_d"],c},programs:[],program:function(a,b,c,d,e){var g=this.programs[a],h=this.fn(a);return b||e||d||c?g=f(this,a,h,b,c,d,e):g||(g=this.programs[a]=f(this,a,h)),g},data:function(a,b){for(;a&&b--;)a=a._parent;return a},merge:function(a,b){var c=a||b;return a&&b&&a!==b&&(c=o.extend({},b,a)),c},noop:b.VM.noop,compilerInfo:a.compiler};return d.isTop=!0,d._setup=function(c){c.partial?(e.helpers=c.helpers,e.partials=c.partials,e.decorators=c.decorators):(e.helpers=e.merge(c.helpers,b.helpers),a.usePartial&&(e.partials=e.merge(c.partials,b.partials)),(a.usePartial||a.useDecorators)&&(e.decorators=e.merge(c.decorators,b.decorators)))},d._child=function(b,c,d,g){if(a.useBlockParams&&!d)throw new q["default"]("must pass block params");if(a.useDepths&&!g)throw new q["default"]("must pass parent depths");return f(e,b,a[b],c,0,d,g)},d}function f(a,b,c,d,e,f,g){function h(b){var e=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],h=g;return g&&b!==g[0]&&(h=[b].concat(g)),c(a,b,a.helpers,a.partials,e.data||d,f&&[e.blockParams].concat(f),h)}return h=k(c,h,a,g,d,f),h.program=b,h.depth=g?g.length:0,h.blockParams=e||0,h}function g(a,b,c){return a?a.call||c.name||(c.name=a,a=c.partials[a]):a="@partial-block"===c.name?c.data["partial-block"]:c.partials[c.name],a}function h(a,b,c){c.partial=!0,c.ids&&(c.data.contextPath=c.ids[0]||c.data.contextPath);var d=void 0;if(c.fn&&c.fn!==i&&(c.data=r.createFrame(c.data),d=c.data["partial-block"]=c.fn,d.partials&&(c.partials=o.extend({},c.partials,d.partials))),void 0===a&&d&&(a=d),void 0===a)throw new q["default"]("The partial "+c.name+" could not be found");return a instanceof Function?a(b,c):void 0}function i(){return""}function j(a,b){return b&&"root"in b||(b=b?r.createFrame(b):{},b.root=a),b}function k(a,b,c,d,e,f){if(a.decorator){var g={};b=a.decorator(b,g,c,d&&d[0],e,f,d),o.extend(b,g)}return b}var l=c(3)["default"],m=c(1)["default"];b.__esModule=!0,b.checkRevision=d,b.template=e,b.wrapProgram=f,b.resolvePartial=g,b.invokePartial=h,b.noop=i;var n=c(5),o=l(n),p=c(6),q=m(p),r=c(4)},function(a,b){(function(c){"use strict";b.__esModule=!0,b["default"]=function(a){var b="undefined"!=typeof c?c:window,d=b.Handlebars;a.noConflict=function(){return b.Handlebars===a&&(b.Handlebars=d),a}},a.exports=b["default"]}).call(b,function(){return this}())},function(a,b){"use strict";b.__esModule=!0;var c={helpers:{helperExpression:function(a){return"SubExpression"===a.type||("MustacheStatement"===a.type||"BlockStatement"===a.type)&&!!(a.params&&a.params.length||a.hash)},scopedId:function(a){return/^\.|this\b/.test(a.original)},simpleId:function(a){return 1===a.parts.length&&!c.helpers.scopedId(a)&&!a.depth}}};b["default"]=c,a.exports=b["default"]},function(a,b,c){"use strict";function d(a,b){if("Program"===a.type)return a;h["default"].yy=n,n.locInfo=function(a){return new n.SourceLocation(b&&b.srcName,a)};var c=new j["default"](b);return c.accept(h["default"].parse(a))}var e=c(1)["default"],f=c(3)["default"];b.__esModule=!0,b.parse=d;var g=c(23),h=e(g),i=c(24),j=e(i),k=c(26),l=f(k),m=c(5);b.parser=h["default"];var n={};m.extend(n,l)},function(a,b){"use strict";var c=function(){function a(){this.yy={}}var b={trace:function(){},yy:{},symbols_:{error:2,root:3,program:4,EOF:5,program_repetition0:6,statement:7,mustache:8,block:9,rawBlock:10,partial:11,partialBlock:12,content:13,COMMENT:14,CONTENT:15,openRawBlock:16,rawBlock_repetition_plus0:17,END_RAW_BLOCK:18,OPEN_RAW_BLOCK:19,helperName:20,openRawBlock_repetition0:21,openRawBlock_option0:22,CLOSE_RAW_BLOCK:23,openBlock:24,block_option0:25,closeBlock:26,openInverse:27,block_option1:28,OPEN_BLOCK:29,openBlock_repetition0:30,openBlock_option0:31,openBlock_option1:32,CLOSE:33,OPEN_INVERSE:34,openInverse_repetition0:35,openInverse_option0:36,openInverse_option1:37,openInverseChain:38,OPEN_INVERSE_CHAIN:39,openInverseChain_repetition0:40,openInverseChain_option0:41,openInverseChain_option1:42,inverseAndProgram:43,INVERSE:44,inverseChain:45,inverseChain_option0:46,OPEN_ENDBLOCK:47,OPEN:48,mustache_repetition0:49,mustache_option0:50,OPEN_UNESCAPED:51,mustache_repetition1:52,mustache_option1:53,CLOSE_UNESCAPED:54,OPEN_PARTIAL:55,partialName:56,partial_repetition0:57,partial_option0:58,openPartialBlock:59,OPEN_PARTIAL_BLOCK:60,openPartialBlock_repetition0:61,openPartialBlock_option0:62,param:63,sexpr:64,OPEN_SEXPR:65,sexpr_repetition0:66,sexpr_option0:67,CLOSE_SEXPR:68,hash:69,hash_repetition_plus0:70,hashSegment:71,ID:72,EQUALS:73,blockParams:74,OPEN_BLOCK_PARAMS:75,blockParams_repetition_plus0:76,CLOSE_BLOCK_PARAMS:77,path:78,dataName:79,STRING:80,NUMBER:81,BOOLEAN:82,UNDEFINED:83,NULL:84,DATA:85,pathSegments:86,SEP:87,$accept:0,$end:1},terminals_:{2:"error",5:"EOF",14:"COMMENT",15:"CONTENT",18:"END_RAW_BLOCK",19:"OPEN_RAW_BLOCK",23:"CLOSE_RAW_BLOCK",29:"OPEN_BLOCK",33:"CLOSE",34:"OPEN_INVERSE",39:"OPEN_INVERSE_CHAIN",44:"INVERSE",47:"OPEN_ENDBLOCK",48:"OPEN",51:"OPEN_UNESCAPED",54:"CLOSE_UNESCAPED",55:"OPEN_PARTIAL",60:"OPEN_PARTIAL_BLOCK",65:"OPEN_SEXPR",68:"CLOSE_SEXPR",72:"ID",73:"EQUALS",75:"OPEN_BLOCK_PARAMS",77:"CLOSE_BLOCK_PARAMS",80:"STRING",81:"NUMBER",82:"BOOLEAN",83:"UNDEFINED",84:"NULL",85:"DATA",87:"SEP"},productions_:[0,[3,2],[4,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[13,1],[10,3],[16,5],[9,4],[9,4],[24,6],[27,6],[38,6],[43,2],[45,3],[45,1],[26,3],[8,5],[8,5],[11,5],[12,3],[59,5],[63,1],[63,1],[64,5],[69,1],[71,3],[74,3],[20,1],[20,1],[20,1],[20,1],[20,1],[20,1],[20,1],[56,1],[56,1],[79,2],[78,1],[86,3],[86,1],[6,0],[6,2],[17,1],[17,2],[21,0],[21,2],[22,0],[22,1],[25,0],[25,1],[28,0],[28,1],[30,0],[30,2],[31,0],[31,1],[32,0],[32,1],[35,0],[35,2],[36,0],[36,1],[37,0],[37,1],[40,0],[40,2],[41,0],[41,1],[42,0],[42,1],[46,0],[46,1],[49,0],[49,2],[50,0],[50,1],[52,0],[52,2],[53,0],[53,1],[57,0],[57,2],[58,0],[58,1],[61,0],[61,2],[62,0],[62,1],[66,0],[66,2],[67,0],[67,1],[70,1],[70,2],[76,1],[76,2]],performAction:function(a,b,c,d,e,f,g){var h=f.length-1;switch(e){case 1:return f[h-1];case 2:this.$=d.prepareProgram(f[h]);break;case 3:this.$=f[h];break;case 4:this.$=f[h];break;case 5:this.$=f[h];break;case 6:this.$=f[h];break;case 7:this.$=f[h];break;case 8:this.$=f[h];break;case 9:this.$={type:"CommentStatement",value:d.stripComment(f[h]),strip:d.stripFlags(f[h],f[h]),loc:d.locInfo(this._$)};break;case 10:this.$={type:"ContentStatement",original:f[h],value:f[h],loc:d.locInfo(this._$)};break;case 11:this.$=d.prepareRawBlock(f[h-2],f[h-1],f[h],this._$);break;case 12:this.$={path:f[h-3],params:f[h-2],hash:f[h-1]};break;case 13:this.$=d.prepareBlock(f[h-3],f[h-2],f[h-1],f[h],!1,this._$);break;case 14:this.$=d.prepareBlock(f[h-3],f[h-2],f[h-1],f[h],!0,this._$);break;case 15:this.$={open:f[h-5],path:f[h-4],params:f[h-3],hash:f[h-2],blockParams:f[h-1],strip:d.stripFlags(f[h-5],f[h])};break;case 16:this.$={path:f[h-4],params:f[h-3],hash:f[h-2],blockParams:f[h-1],strip:d.stripFlags(f[h-5],f[h])};break;case 17:this.$={path:f[h-4],params:f[h-3],hash:f[h-2],blockParams:f[h-1],strip:d.stripFlags(f[h-5],f[h])};break;case 18:this.$={strip:d.stripFlags(f[h-1],f[h-1]),program:f[h]};break;case 19:var i=d.prepareBlock(f[h-2],f[h-1],f[h],f[h],!1,this._$),j=d.prepareProgram([i],f[h-1].loc);j.chained=!0,this.$={strip:f[h-2].strip,program:j,chain:!0};break;case 20:this.$=f[h];break;case 21:this.$={path:f[h-1],strip:d.stripFlags(f[h-2],f[h])};break;case 22:this.$=d.prepareMustache(f[h-3],f[h-2],f[h-1],f[h-4],d.stripFlags(f[h-4],f[h]),this._$);break;case 23:this.$=d.prepareMustache(f[h-3],f[h-2],f[h-1],f[h-4],d.stripFlags(f[h-4],f[h]),this._$);break;case 24:this.$={type:"PartialStatement",name:f[h-3],params:f[h-2],hash:f[h-1],indent:"",strip:d.stripFlags(f[h-4],f[h]),loc:d.locInfo(this._$)};break;case 25:this.$=d.preparePartialBlock(f[h-2],f[h-1],f[h],this._$);break;case 26:this.$={path:f[h-3],params:f[h-2],hash:f[h-1],strip:d.stripFlags(f[h-4],f[h])};break;case 27:this.$=f[h];break;case 28:this.$=f[h];break;case 29:this.$={type:"SubExpression",path:f[h-3],params:f[h-2],hash:f[h-1],loc:d.locInfo(this._$)};break;case 30:this.$={type:"Hash",pairs:f[h],loc:d.locInfo(this._$)};break;case 31:this.$={type:"HashPair",key:d.id(f[h-2]),value:f[h],loc:d.locInfo(this._$)};break;case 32:this.$=d.id(f[h-1]);break;case 33:this.$=f[h];break;case 34:this.$=f[h];break;case 35:this.$={type:"StringLiteral",value:f[h],original:f[h],loc:d.locInfo(this._$)};break;case 36:this.$={type:"NumberLiteral",value:Number(f[h]),original:Number(f[h]),loc:d.locInfo(this._$)};break;case 37:this.$={type:"BooleanLiteral",value:"true"===f[h],original:"true"===f[h],loc:d.locInfo(this._$)};break;case 38:this.$={type:"UndefinedLiteral",original:void 0,value:void 0,loc:d.locInfo(this._$)};break;case 39:this.$={type:"NullLiteral",original:null,value:null,loc:d.locInfo(this._$)};break;case 40:this.$=f[h];break;case 41:this.$=f[h];break;case 42:this.$=d.preparePath(!0,f[h],this._$);break;case 43:this.$=d.preparePath(!1,f[h],this._$);break;case 44:f[h-2].push({part:d.id(f[h]),original:f[h],separator:f[h-1]}),this.$=f[h-2];break;case 45:this.$=[{part:d.id(f[h]),original:f[h]}];break;case 46:this.$=[];break;case 47:f[h-1].push(f[h]);break;case 48:this.$=[f[h]];break;case 49:f[h-1].push(f[h]);break;case 50:this.$=[];break;case 51:f[h-1].push(f[h]);break;case 58:this.$=[];break;case 59:f[h-1].push(f[h]);break;case 64:this.$=[];break;case 65:f[h-1].push(f[h]);break;case 70:this.$=[];break;case 71:f[h-1].push(f[h]);break;case 78:this.$=[];break;case 79:f[h-1].push(f[h]);break;case 82:this.$=[];break;case 83:f[h-1].push(f[h]);break;case 86:this.$=[];break;case 87:f[h-1].push(f[h]);break;case 90:this.$=[];break;case 91:f[h-1].push(f[h]);break;case 94:this.$=[];break;case 95:f[h-1].push(f[h]);break;case 98:this.$=[f[h]];break;case 99:f[h-1].push(f[h]);break;case 100:this.$=[f[h]];break;case 101:f[h-1].push(f[h])}},table:[{3:1,4:2,5:[2,46],6:3,14:[2,46],15:[2,46],19:[2,46],29:[2,46],34:[2,46],48:[2,46],51:[2,46],55:[2,46],60:[2,46]},{1:[3]},{5:[1,4]},{5:[2,2],7:5,8:6,9:7,10:8,11:9,12:10,13:11,14:[1,12],15:[1,20],16:17,19:[1,23],24:15,27:16,29:[1,21],34:[1,22],39:[2,2],44:[2,2],47:[2,2],48:[1,13],51:[1,14],55:[1,18],59:19,60:[1,24]},{1:[2,1]},{5:[2,47],14:[2,47],15:[2,47],19:[2,47],29:[2,47],34:[2,47],39:[2,47],44:[2,47],47:[2,47],48:[2,47],51:[2,47],55:[2,47],60:[2,47]},{5:[2,3],14:[2,3],15:[2,3],19:[2,3],29:[2,3],34:[2,3],39:[2,3],44:[2,3],47:[2,3],48:[2,3],51:[2,3],55:[2,3],60:[2,3]},{5:[2,4],14:[2,4],15:[2,4],19:[2,4],29:[2,4],34:[2,4],39:[2,4],44:[2,4],47:[2,4],48:[2,4],51:[2,4],55:[2,4],60:[2,4]},{5:[2,5],14:[2,5],15:[2,5],19:[2,5],29:[2,5],34:[2,5],39:[2,5],44:[2,5],47:[2,5],48:[2,5],51:[2,5],55:[2,5],60:[2,5]},{5:[2,6],14:[2,6],15:[2,6],19:[2,6],29:[2,6],34:[2,6],39:[2,6],44:[2,6],47:[2,6],48:[2,6],51:[2,6],55:[2,6],60:[2,6]},{5:[2,7],14:[2,7],15:[2,7],19:[2,7],29:[2,7],34:[2,7],39:[2,7],44:[2,7],47:[2,7],48:[2,7],51:[2,7],55:[2,7],60:[2,7]},{5:[2,8],14:[2,8],15:[2,8],19:[2,8],29:[2,8],34:[2,8],39:[2,8],44:[2,8],47:[2,8],48:[2,8],51:[2,8],55:[2,8],60:[2,8]},{5:[2,9],14:[2,9],15:[2,9],19:[2,9],29:[2,9],34:[2,9],39:[2,9],44:[2,9],47:[2,9],48:[2,9],51:[2,9],55:[2,9],60:[2,9]},{20:25,72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{20:36,72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{4:37,6:3,14:[2,46],15:[2,46],19:[2,46],29:[2,46],34:[2,46],39:[2,46],44:[2,46],47:[2,46],48:[2,46],51:[2,46],55:[2,46],60:[2,46]},{4:38,6:3,14:[2,46],15:[2,46],19:[2,46],29:[2,46],34:[2,46],44:[2,46],47:[2,46],48:[2,46],51:[2,46],55:[2,46],60:[2,46]},{13:40,15:[1,20],17:39},{20:42,56:41,64:43,65:[1,44],72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{4:45,6:3,14:[2,46],15:[2,46],19:[2,46],29:[2,46],34:[2,46],47:[2,46],48:[2,46],51:[2,46],55:[2,46],60:[2,46]},{5:[2,10],14:[2,10],15:[2,10],18:[2,10],19:[2,10],29:[2,10],34:[2,10],39:[2,10],44:[2,10],47:[2,10],48:[2,10],51:[2,10],55:[2,10],60:[2,10]},{20:46,72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{20:47,72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{20:48,72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{20:42,56:49,64:43,65:[1,44],72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{33:[2,78],49:50,65:[2,78],72:[2,78],80:[2,78],81:[2,78],82:[2,78],83:[2,78],84:[2,78],85:[2,78]},{23:[2,33],33:[2,33],54:[2,33],65:[2,33],68:[2,33],72:[2,33],75:[2,33],80:[2,33],81:[2,33],82:[2,33],83:[2,33],84:[2,33],85:[2,33]},{23:[2,34],33:[2,34],54:[2,34],65:[2,34],68:[2,34],72:[2,34],75:[2,34],80:[2,34],81:[2,34],82:[2,34],83:[2,34],84:[2,34],85:[2,34]},{23:[2,35],33:[2,35],54:[2,35],65:[2,35],68:[2,35],72:[2,35],75:[2,35],80:[2,35],81:[2,35],82:[2,35],83:[2,35],84:[2,35],85:[2,35]},{23:[2,36],33:[2,36],54:[2,36],65:[2,36],68:[2,36],72:[2,36],75:[2,36],80:[2,36],81:[2,36],82:[2,36],83:[2,36],84:[2,36],85:[2,36]},{23:[2,37],33:[2,37],54:[2,37],65:[2,37],68:[2,37],72:[2,37],75:[2,37],80:[2,37],81:[2,37],82:[2,37],83:[2,37],84:[2,37],85:[2,37]},{23:[2,38],33:[2,38],54:[2,38],65:[2,38],68:[2,38],72:[2,38],75:[2,38],80:[2,38],81:[2,38],82:[2,38],83:[2,38],84:[2,38],85:[2,38]},{23:[2,39],33:[2,39],54:[2,39],65:[2,39],68:[2,39],72:[2,39],75:[2,39],80:[2,39],81:[2,39],82:[2,39],83:[2,39],84:[2,39],85:[2,39]},{23:[2,43],33:[2,43],54:[2,43],65:[2,43],68:[2,43],72:[2,43],75:[2,43],80:[2,43],81:[2,43],82:[2,43],83:[2,43],84:[2,43],85:[2,43],87:[1,51]},{72:[1,35],86:52},{23:[2,45],33:[2,45],54:[2,45],65:[2,45],68:[2,45],72:[2,45],75:[2,45],80:[2,45],81:[2,45],82:[2,45],83:[2,45],84:[2,45],85:[2,45],87:[2,45]},{52:53,54:[2,82],65:[2,82],72:[2,82],80:[2,82],81:[2,82],82:[2,82],83:[2,82],84:[2,82],85:[2,82]},{25:54,38:56,39:[1,58],43:57,44:[1,59],45:55,47:[2,54]},{28:60,43:61,44:[1,59],47:[2,56]},{13:63,15:[1,20],18:[1,62]},{15:[2,48],18:[2,48]},{33:[2,86],57:64,65:[2,86],72:[2,86],80:[2,86],81:[2,86],82:[2,86],83:[2,86],84:[2,86],85:[2,86]},{33:[2,40],65:[2,40],72:[2,40],80:[2,40],81:[2,40],82:[2,40],83:[2,40],84:[2,40],85:[2,40]},{33:[2,41],65:[2,41],72:[2,41],80:[2,41],81:[2,41],82:[2,41],83:[2,41],84:[2,41],85:[2,41]},{20:65,72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{26:66,47:[1,67]},{30:68,33:[2,58],65:[2,58],72:[2,58],75:[2,58],80:[2,58],81:[2,58],82:[2,58],83:[2,58],84:[2,58],85:[2,58]},{33:[2,64],35:69,65:[2,64],72:[2,64],75:[2,64],80:[2,64],81:[2,64],82:[2,64],83:[2,64],84:[2,64],85:[2,64]},{21:70,23:[2,50],65:[2,50],72:[2,50],80:[2,50],81:[2,50],82:[2,50],83:[2,50],84:[2,50],85:[2,50]},{33:[2,90],61:71,65:[2,90],72:[2,90],80:[2,90],81:[2,90],82:[2,90],83:[2,90],84:[2,90],85:[2,90]},{20:75,33:[2,80],50:72,63:73,64:76,65:[1,44],69:74,70:77,71:78,72:[1,79],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{72:[1,80]},{23:[2,42],33:[2,42],54:[2,42],65:[2,42],68:[2,42],72:[2,42],75:[2,42],80:[2,42],81:[2,42],82:[2,42],83:[2,42],84:[2,42],85:[2,42],87:[1,51]},{20:75,53:81,54:[2,84],63:82,64:76,65:[1,44],69:83,70:77,71:78,72:[1,79],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{26:84,47:[1,67]},{47:[2,55]},{4:85,6:3,14:[2,46],15:[2,46],19:[2,46],29:[2,46],34:[2,46],39:[2,46],44:[2,46],47:[2,46],48:[2,46],51:[2,46],55:[2,46],60:[2,46]},{47:[2,20]},{20:86,72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{4:87,6:3,14:[2,46],15:[2,46],19:[2,46],29:[2,46],34:[2,46],47:[2,46],48:[2,46],51:[2,46],55:[2,46],60:[2,46]},{26:88,47:[1,67]},{47:[2,57]},{5:[2,11],14:[2,11],15:[2,11],19:[2,11],29:[2,11],34:[2,11],39:[2,11],44:[2,11],47:[2,11],48:[2,11],51:[2,11],55:[2,11],60:[2,11]},{15:[2,49],18:[2,49]},{20:75,33:[2,88],58:89,63:90,64:76,65:[1,44],69:91,70:77,71:78,72:[1,79],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{65:[2,94],66:92,68:[2,94],72:[2,94],80:[2,94],81:[2,94],82:[2,94],83:[2,94],84:[2,94],85:[2,94]},{5:[2,25],14:[2,25],15:[2,25],19:[2,25],29:[2,25],34:[2,25],39:[2,25],44:[2,25],47:[2,25],48:[2,25],51:[2,25],55:[2,25],60:[2,25]},{20:93,72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{20:75,31:94,33:[2,60],63:95,64:76,65:[1,44],69:96,70:77,71:78,72:[1,79],75:[2,60],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{20:75,33:[2,66],36:97,63:98,64:76,65:[1,44],69:99,70:77,71:78,72:[1,79],75:[2,66],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{20:75,22:100,23:[2,52],63:101,64:76,65:[1,44],69:102,70:77,71:78,72:[1,79],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{20:75,33:[2,92],62:103,63:104,64:76,65:[1,44],69:105,70:77,71:78,72:[1,79],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{33:[1,106]},{33:[2,79],65:[2,79],72:[2,79],80:[2,79],81:[2,79],82:[2,79],83:[2,79],84:[2,79],85:[2,79]},{33:[2,81]},{23:[2,27],33:[2,27],54:[2,27],65:[2,27],68:[2,27],72:[2,27],75:[2,27],80:[2,27],81:[2,27],82:[2,27],83:[2,27],84:[2,27],85:[2,27]},{23:[2,28],33:[2,28],54:[2,28],65:[2,28],68:[2,28],72:[2,28],75:[2,28],80:[2,28],81:[2,28],82:[2,28],83:[2,28],84:[2,28],85:[2,28]},{23:[2,30],33:[2,30],54:[2,30],68:[2,30],71:107,72:[1,108],75:[2,30]},{23:[2,98],33:[2,98],54:[2,98],68:[2,98],72:[2,98],75:[2,98]},{23:[2,45],33:[2,45],54:[2,45],65:[2,45],68:[2,45],72:[2,45],73:[1,109],75:[2,45],80:[2,45],81:[2,45],82:[2,45],83:[2,45],84:[2,45],85:[2,45],87:[2,45]},{23:[2,44],33:[2,44],54:[2,44],65:[2,44],68:[2,44],72:[2,44],75:[2,44],80:[2,44],81:[2,44],82:[2,44],83:[2,44],84:[2,44],85:[2,44],87:[2,44]},{54:[1,110]},{54:[2,83],65:[2,83],72:[2,83],80:[2,83],81:[2,83],82:[2,83],83:[2,83],84:[2,83],85:[2,83]},{54:[2,85]},{5:[2,13],14:[2,13],15:[2,13],19:[2,13],29:[2,13],34:[2,13],39:[2,13],44:[2,13],47:[2,13],48:[2,13],51:[2,13],55:[2,13],60:[2,13]},{38:56,39:[1,58],43:57,44:[1,59],45:112,46:111,47:[2,76]},{33:[2,70],40:113,65:[2,70],72:[2,70],75:[2,70],80:[2,70],81:[2,70],82:[2,70],83:[2,70],84:[2,70],85:[2,70]},{47:[2,18]},{5:[2,14],14:[2,14],15:[2,14],19:[2,14],29:[2,14],34:[2,14],39:[2,14],44:[2,14],47:[2,14],48:[2,14],51:[2,14],55:[2,14],60:[2,14]},{33:[1,114]},{33:[2,87],65:[2,87],72:[2,87],80:[2,87],81:[2,87],82:[2,87],83:[2,87],84:[2,87],85:[2,87]},{33:[2,89]},{20:75,63:116,64:76,65:[1,44],67:115,68:[2,96],69:117,70:77,71:78,72:[1,79],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{33:[1,118]},{32:119,33:[2,62],74:120,75:[1,121]},{33:[2,59],65:[2,59],72:[2,59],75:[2,59],80:[2,59],81:[2,59],82:[2,59],83:[2,59],84:[2,59],85:[2,59]},{33:[2,61],75:[2,61]},{33:[2,68],37:122,74:123,75:[1,121]},{33:[2,65],65:[2,65],72:[2,65],75:[2,65],80:[2,65],81:[2,65],82:[2,65],83:[2,65],84:[2,65],85:[2,65]},{33:[2,67],75:[2,67]},{23:[1,124]},{23:[2,51],65:[2,51],72:[2,51],80:[2,51],81:[2,51],82:[2,51],83:[2,51],84:[2,51],85:[2,51]},{23:[2,53]},{33:[1,125]},{33:[2,91],65:[2,91],72:[2,91],80:[2,91],81:[2,91],82:[2,91],83:[2,91],84:[2,91],85:[2,91]},{33:[2,93]},{5:[2,22],14:[2,22],15:[2,22],19:[2,22],29:[2,22],34:[2,22],39:[2,22],44:[2,22],47:[2,22],48:[2,22],51:[2,22],55:[2,22],60:[2,22]},{23:[2,99],33:[2,99],54:[2,99],68:[2,99],72:[2,99],75:[2,99]},{73:[1,109]},{20:75,63:126,64:76,65:[1,44],72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{5:[2,23],14:[2,23],15:[2,23],19:[2,23],29:[2,23],34:[2,23],39:[2,23],44:[2,23],47:[2,23],48:[2,23],51:[2,23],55:[2,23],60:[2,23]},{47:[2,19]},{47:[2,77]},{20:75,33:[2,72],41:127,63:128,64:76,65:[1,44],69:129,70:77,71:78,72:[1,79],75:[2,72],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{5:[2,24],14:[2,24],15:[2,24],19:[2,24],29:[2,24],34:[2,24],39:[2,24],44:[2,24],47:[2,24],48:[2,24],51:[2,24],55:[2,24],60:[2,24]},{68:[1,130]},{65:[2,95],68:[2,95],72:[2,95],80:[2,95],81:[2,95],82:[2,95],83:[2,95],84:[2,95],85:[2,95]},{68:[2,97]},{5:[2,21],14:[2,21],15:[2,21],19:[2,21],29:[2,21],34:[2,21],39:[2,21],44:[2,21],47:[2,21],48:[2,21],51:[2,21],55:[2,21],60:[2,21]},{33:[1,131]},{33:[2,63]},{72:[1,133],76:132},{33:[1,134]},{33:[2,69]},{15:[2,12]},{14:[2,26],15:[2,26],19:[2,26],29:[2,26],34:[2,26],47:[2,26],48:[2,26],51:[2,26],55:[2,26],60:[2,26]},{23:[2,31],33:[2,31],54:[2,31],68:[2,31],72:[2,31],75:[2,31]},{33:[2,74],42:135,74:136,75:[1,121]},{33:[2,71],65:[2,71],72:[2,71],75:[2,71],80:[2,71],81:[2,71],82:[2,71],83:[2,71],84:[2,71],85:[2,71]},{33:[2,73],75:[2,73]},{23:[2,29],33:[2,29],54:[2,29],65:[2,29],68:[2,29],72:[2,29],75:[2,29],80:[2,29],81:[2,29],82:[2,29],83:[2,29],84:[2,29],85:[2,29]},{14:[2,15],15:[2,15],19:[2,15],29:[2,15],34:[2,15],39:[2,15],44:[2,15],47:[2,15],48:[2,15],51:[2,15],55:[2,15],60:[2,15]},{72:[1,138],77:[1,137]},{72:[2,100],77:[2,100]},{14:[2,16],15:[2,16],19:[2,16],29:[2,16],34:[2,16],44:[2,16],47:[2,16], -48:[2,16],51:[2,16],55:[2,16],60:[2,16]},{33:[1,139]},{33:[2,75]},{33:[2,32]},{72:[2,101],77:[2,101]},{14:[2,17],15:[2,17],19:[2,17],29:[2,17],34:[2,17],39:[2,17],44:[2,17],47:[2,17],48:[2,17],51:[2,17],55:[2,17],60:[2,17]}],defaultActions:{4:[2,1],55:[2,55],57:[2,20],61:[2,57],74:[2,81],83:[2,85],87:[2,18],91:[2,89],102:[2,53],105:[2,93],111:[2,19],112:[2,77],117:[2,97],120:[2,63],123:[2,69],124:[2,12],136:[2,75],137:[2,32]},parseError:function(a,b){throw new Error(a)},parse:function(a){function b(){var a;return a=c.lexer.lex()||1,"number"!=typeof a&&(a=c.symbols_[a]||a),a}var c=this,d=[0],e=[null],f=[],g=this.table,h="",i=0,j=0,k=0;this.lexer.setInput(a),this.lexer.yy=this.yy,this.yy.lexer=this.lexer,this.yy.parser=this,"undefined"==typeof this.lexer.yylloc&&(this.lexer.yylloc={});var l=this.lexer.yylloc;f.push(l);var m=this.lexer.options&&this.lexer.options.ranges;"function"==typeof this.yy.parseError&&(this.parseError=this.yy.parseError);for(var n,o,p,q,r,s,t,u,v,w={};;){if(p=d[d.length-1],this.defaultActions[p]?q=this.defaultActions[p]:((null===n||"undefined"==typeof n)&&(n=b()),q=g[p]&&g[p][n]),"undefined"==typeof q||!q.length||!q[0]){var x="";if(!k){v=[];for(s in g[p])this.terminals_[s]&&s>2&&v.push("'"+this.terminals_[s]+"'");x=this.lexer.showPosition?"Parse error on line "+(i+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+v.join(", ")+", got '"+(this.terminals_[n]||n)+"'":"Parse error on line "+(i+1)+": Unexpected "+(1==n?"end of input":"'"+(this.terminals_[n]||n)+"'"),this.parseError(x,{text:this.lexer.match,token:this.terminals_[n]||n,line:this.lexer.yylineno,loc:l,expected:v})}}if(q[0]instanceof Array&&q.length>1)throw new Error("Parse Error: multiple actions possible at state: "+p+", token: "+n);switch(q[0]){case 1:d.push(n),e.push(this.lexer.yytext),f.push(this.lexer.yylloc),d.push(q[1]),n=null,o?(n=o,o=null):(j=this.lexer.yyleng,h=this.lexer.yytext,i=this.lexer.yylineno,l=this.lexer.yylloc,k>0&&k--);break;case 2:if(t=this.productions_[q[1]][1],w.$=e[e.length-t],w._$={first_line:f[f.length-(t||1)].first_line,last_line:f[f.length-1].last_line,first_column:f[f.length-(t||1)].first_column,last_column:f[f.length-1].last_column},m&&(w._$.range=[f[f.length-(t||1)].range[0],f[f.length-1].range[1]]),r=this.performAction.call(w,h,j,i,this.yy,q[1],e,f),"undefined"!=typeof r)return r;t&&(d=d.slice(0,-1*t*2),e=e.slice(0,-1*t),f=f.slice(0,-1*t)),d.push(this.productions_[q[1]][0]),e.push(w.$),f.push(w._$),u=g[d[d.length-2]][d[d.length-1]],d.push(u);break;case 3:return!0}}return!0}},c=function(){var a={EOF:1,parseError:function(a,b){if(!this.yy.parser)throw new Error(a);this.yy.parser.parseError(a,b)},setInput:function(a){return this._input=a,this._more=this._less=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var a=this._input[0];this.yytext+=a,this.yyleng++,this.offset++,this.match+=a,this.matched+=a;var b=a.match(/(?:\r\n?|\n).*/g);return b?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),a},unput:function(a){var b=a.length,c=a.split(/(?:\r\n?|\n)/g);this._input=a+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-b-1),this.offset-=b;var d=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),c.length-1&&(this.yylineno-=c.length-1);var e=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:c?(c.length===d.length?this.yylloc.first_column:0)+d[d.length-c.length].length-c[0].length:this.yylloc.first_column-b},this.options.ranges&&(this.yylloc.range=[e[0],e[0]+this.yyleng-b]),this},more:function(){return this._more=!0,this},less:function(a){this.unput(this.match.slice(a))},pastInput:function(){var a=this.matched.substr(0,this.matched.length-this.match.length);return(a.length>20?"...":"")+a.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var a=this.match;return a.length<20&&(a+=this._input.substr(0,20-a.length)),(a.substr(0,20)+(a.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var a=this.pastInput(),b=new Array(a.length+1).join("-");return a+this.upcomingInput()+"\n"+b+"^"},next:function(){if(this.done)return this.EOF;this._input||(this.done=!0);var a,b,c,d,e;this._more||(this.yytext="",this.match="");for(var f=this._currentRules(),g=0;gb[0].length)||(b=c,d=g,this.options.flex));g++);return b?(e=b[0].match(/(?:\r\n?|\n).*/g),e&&(this.yylineno+=e.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:e?e[e.length-1].length-e[e.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+b[0].length},this.yytext+=b[0],this.match+=b[0],this.matches=b,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._input=this._input.slice(b[0].length),this.matched+=b[0],a=this.performAction.call(this,this.yy,this,f[d],this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),a?a:void 0):""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var a=this.next();return"undefined"!=typeof a?a:this.lex()},begin:function(a){this.conditionStack.push(a)},popState:function(){return this.conditionStack.pop()},_currentRules:function(){return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules},topState:function(){return this.conditionStack[this.conditionStack.length-2]},pushState:function(a){this.begin(a)}};return a.options={},a.performAction=function(a,b,c,d){function e(a,c){return b.yytext=b.yytext.substr(a,b.yyleng-c)}switch(c){case 0:if("\\\\"===b.yytext.slice(-2)?(e(0,1),this.begin("mu")):"\\"===b.yytext.slice(-1)?(e(0,1),this.begin("emu")):this.begin("mu"),b.yytext)return 15;break;case 1:return 15;case 2:return this.popState(),15;case 3:return this.begin("raw"),15;case 4:return this.popState(),"raw"===this.conditionStack[this.conditionStack.length-1]?15:(b.yytext=b.yytext.substr(5,b.yyleng-9),"END_RAW_BLOCK");case 5:return 15;case 6:return this.popState(),14;case 7:return 65;case 8:return 68;case 9:return 19;case 10:return this.popState(),this.begin("raw"),23;case 11:return 55;case 12:return 60;case 13:return 29;case 14:return 47;case 15:return this.popState(),44;case 16:return this.popState(),44;case 17:return 34;case 18:return 39;case 19:return 51;case 20:return 48;case 21:this.unput(b.yytext),this.popState(),this.begin("com");break;case 22:return this.popState(),14;case 23:return 48;case 24:return 73;case 25:return 72;case 26:return 72;case 27:return 87;case 28:break;case 29:return this.popState(),54;case 30:return this.popState(),33;case 31:return b.yytext=e(1,2).replace(/\\"/g,'"'),80;case 32:return b.yytext=e(1,2).replace(/\\'/g,"'"),80;case 33:return 85;case 34:return 82;case 35:return 82;case 36:return 83;case 37:return 84;case 38:return 81;case 39:return 75;case 40:return 77;case 41:return 72;case 42:return b.yytext=b.yytext.replace(/\\([\\\]])/g,"$1"),72;case 43:return"INVALID";case 44:return 5}},a.rules=[/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/,/^(?:\{\{\{\{(?=[^\/]))/,/^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/,/^(?:[^\x00]*?(?=(\{\{\{\{)))/,/^(?:[\s\S]*?--(~)?\}\})/,/^(?:\()/,/^(?:\))/,/^(?:\{\{\{\{)/,/^(?:\}\}\}\})/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#>)/,/^(?:\{\{(~)?#\*?)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^\s*(~)?\}\})/,/^(?:\{\{(~)?\s*else\s*(~)?\}\})/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{(~)?!--)/,/^(?:\{\{(~)?![\s\S]*?\}\})/,/^(?:\{\{(~)?\*?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.)|])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s)])))/,/^(?:false(?=([~}\s)])))/,/^(?:undefined(?=([~}\s)])))/,/^(?:null(?=([~}\s)])))/,/^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/,/^(?:as\s+\|)/,/^(?:\|)/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)|]))))/,/^(?:\[(\\\]|[^\]])*\])/,/^(?:.)/,/^(?:$)/],a.conditions={mu:{rules:[7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44],inclusive:!1},emu:{rules:[2],inclusive:!1},com:{rules:[6],inclusive:!1},raw:{rules:[3,4,5],inclusive:!1},INITIAL:{rules:[0,1,44],inclusive:!0}},a}();return b.lexer=c,a.prototype=b,b.Parser=a,new a}();b.__esModule=!0,b["default"]=c},function(a,b,c){"use strict";function d(){var a=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];this.options=a}function e(a,b,c){void 0===b&&(b=a.length);var d=a[b-1],e=a[b-2];return d?"ContentStatement"===d.type?(e||!c?/\r?\n\s*?$/:/(^|\r?\n)\s*?$/).test(d.original):void 0:c}function f(a,b,c){void 0===b&&(b=-1);var d=a[b+1],e=a[b+2];return d?"ContentStatement"===d.type?(e||!c?/^\s*?\r?\n/:/^\s*?(\r?\n|$)/).test(d.original):void 0:c}function g(a,b,c){var d=a[null==b?0:b+1];if(d&&"ContentStatement"===d.type&&(c||!d.rightStripped)){var e=d.value;d.value=d.value.replace(c?/^\s+/:/^[ \t]*\r?\n?/,""),d.rightStripped=d.value!==e}}function h(a,b,c){var d=a[null==b?a.length-1:b-1];if(d&&"ContentStatement"===d.type&&(c||!d.leftStripped)){var e=d.value;return d.value=d.value.replace(c?/\s+$/:/[ \t]+$/,""),d.leftStripped=d.value!==e,d.leftStripped}}var i=c(1)["default"];b.__esModule=!0;var j=c(25),k=i(j);d.prototype=new k["default"],d.prototype.Program=function(a){var b=!this.options.ignoreStandalone,c=!this.isRootSeen;this.isRootSeen=!0;for(var d=a.body,i=0,j=d.length;j>i;i++){var k=d[i],l=this.accept(k);if(l){var m=e(d,i,c),n=f(d,i,c),o=l.openStandalone&&m,p=l.closeStandalone&&n,q=l.inlineStandalone&&m&&n;l.close&&g(d,i,!0),l.open&&h(d,i,!0),b&&q&&(g(d,i),h(d,i)&&"PartialStatement"===k.type&&(k.indent=/([ \t]+$)/.exec(d[i-1].original)[1])),b&&o&&(g((k.program||k.inverse).body),h(d,i)),b&&p&&(g(d,i),h((k.inverse||k.program).body))}}return a},d.prototype.BlockStatement=d.prototype.DecoratorBlock=d.prototype.PartialBlockStatement=function(a){this.accept(a.program),this.accept(a.inverse);var b=a.program||a.inverse,c=a.program&&a.inverse,d=c,i=c;if(c&&c.chained)for(d=c.body[0].program;i.chained;)i=i.body[i.body.length-1].program;var j={open:a.openStrip.open,close:a.closeStrip.close,openStandalone:f(b.body),closeStandalone:e((d||b).body)};if(a.openStrip.close&&g(b.body,null,!0),c){var k=a.inverseStrip;k.open&&h(b.body,null,!0),k.close&&g(d.body,null,!0),a.closeStrip.open&&h(i.body,null,!0),!this.options.ignoreStandalone&&e(b.body)&&f(d.body)&&(h(b.body),g(d.body))}else a.closeStrip.open&&h(b.body,null,!0);return j},d.prototype.Decorator=d.prototype.MustacheStatement=function(a){return a.strip},d.prototype.PartialStatement=d.prototype.CommentStatement=function(a){var b=a.strip||{};return{inlineStandalone:!0,open:b.open,close:b.close}},b["default"]=d,a.exports=b["default"]},function(a,b,c){"use strict";function d(){this.parents=[]}function e(a){this.acceptRequired(a,"path"),this.acceptArray(a.params),this.acceptKey(a,"hash")}function f(a){e.call(this,a),this.acceptKey(a,"program"),this.acceptKey(a,"inverse")}function g(a){this.acceptRequired(a,"name"),this.acceptArray(a.params),this.acceptKey(a,"hash")}var h=c(1)["default"];b.__esModule=!0;var i=c(6),j=h(i);d.prototype={constructor:d,mutating:!1,acceptKey:function(a,b){var c=this.accept(a[b]);if(this.mutating){if(c&&!d.prototype[c.type])throw new j["default"]('Unexpected node type "'+c.type+'" found when accepting '+b+" on "+a.type);a[b]=c}},acceptRequired:function(a,b){if(this.acceptKey(a,b),!a[b])throw new j["default"](a.type+" requires "+b)},acceptArray:function(a){for(var b=0,c=a.length;c>b;b++)this.acceptKey(a,b),a[b]||(a.splice(b,1),b--,c--)},accept:function(a){if(a){if(!this[a.type])throw new j["default"]("Unknown type: "+a.type,a);this.current&&this.parents.unshift(this.current),this.current=a;var b=this[a.type](a);return this.current=this.parents.shift(),!this.mutating||b?b:b!==!1?a:void 0}},Program:function(a){this.acceptArray(a.body)},MustacheStatement:e,Decorator:e,BlockStatement:f,DecoratorBlock:f,PartialStatement:g,PartialBlockStatement:function(a){g.call(this,a),this.acceptKey(a,"program")},ContentStatement:function(){},CommentStatement:function(){},SubExpression:e,PathExpression:function(){},StringLiteral:function(){},NumberLiteral:function(){},BooleanLiteral:function(){},UndefinedLiteral:function(){},NullLiteral:function(){},Hash:function(a){this.acceptArray(a.pairs)},HashPair:function(a){this.acceptRequired(a,"value")}},b["default"]=d,a.exports=b["default"]},function(a,b,c){"use strict";function d(a,b){if(b=b.path?b.path.original:b,a.path.original!==b){var c={loc:a.path.loc};throw new q["default"](a.path.original+" doesn't match "+b,c)}}function e(a,b){this.source=a,this.start={line:b.first_line,column:b.first_column},this.end={line:b.last_line,column:b.last_column}}function f(a){return/^\[.*\]$/.test(a)?a.substr(1,a.length-2):a}function g(a,b){return{open:"~"===a.charAt(2),close:"~"===b.charAt(b.length-3)}}function h(a){return a.replace(/^\{\{~?\!-?-?/,"").replace(/-?-?~?\}\}$/,"")}function i(a,b,c){c=this.locInfo(c);for(var d=a?"@":"",e=[],f=0,g="",h=0,i=b.length;i>h;h++){var j=b[h].part,k=b[h].original!==j;if(d+=(b[h].separator||"")+j,k||".."!==j&&"."!==j&&"this"!==j)e.push(j);else{if(e.length>0)throw new q["default"]("Invalid path: "+d,{loc:c});".."===j&&(f++,g+="../")}}return{type:"PathExpression",data:a,depth:f,parts:e,original:d,loc:c}}function j(a,b,c,d,e,f){var g=d.charAt(3)||d.charAt(2),h="{"!==g&&"&"!==g,i=/\*/.test(d);return{type:i?"Decorator":"MustacheStatement",path:a,params:b,hash:c,escaped:h,strip:e,loc:this.locInfo(f)}}function k(a,b,c,e){d(a,c),e=this.locInfo(e);var f={type:"Program",body:b,strip:{},loc:e};return{type:"BlockStatement",path:a.path,params:a.params,hash:a.hash,program:f,openStrip:{},inverseStrip:{},closeStrip:{},loc:e}}function l(a,b,c,e,f,g){e&&e.path&&d(a,e);var h=/\*/.test(a.open);b.blockParams=a.blockParams;var i=void 0,j=void 0;if(c){if(h)throw new q["default"]("Unexpected inverse block on decorator",c);c.chain&&(c.program.body[0].closeStrip=e.strip),j=c.strip,i=c.program}return f&&(f=i,i=b,b=f),{type:h?"DecoratorBlock":"BlockStatement",path:a.path,params:a.params,hash:a.hash,program:b,inverse:i,openStrip:a.strip,inverseStrip:j,closeStrip:e&&e.strip,loc:this.locInfo(g)}}function m(a,b){if(!b&&a.length){var c=a[0].loc,d=a[a.length-1].loc;c&&d&&(b={source:c.source,start:{line:c.start.line,column:c.start.column},end:{line:d.end.line,column:d.end.column}})}return{type:"Program",body:a,strip:{},loc:b}}function n(a,b,c,e){return d(a,c),{type:"PartialBlockStatement",name:a.path,params:a.params,hash:a.hash,program:b,openStrip:a.strip,closeStrip:c&&c.strip,loc:this.locInfo(e)}}var o=c(1)["default"];b.__esModule=!0,b.SourceLocation=e,b.id=f,b.stripFlags=g,b.stripComment=h,b.preparePath=i,b.prepareMustache=j,b.prepareRawBlock=k,b.prepareBlock=l,b.prepareProgram=m,b.preparePartialBlock=n;var p=c(6),q=o(p)},function(a,b,c){"use strict";function d(){}function e(a,b,c){if(null==a||"string"!=typeof a&&"Program"!==a.type)throw new k["default"]("You must pass a string or Handlebars AST to Handlebars.precompile. You passed "+a);b=b||{},"data"in b||(b.data=!0),b.compat&&(b.useDepths=!0);var d=c.parse(a,b),e=(new c.Compiler).compile(d,b);return(new c.JavaScriptCompiler).compile(e,b)}function f(a,b,c){function d(){var d=c.parse(a,b),e=(new c.Compiler).compile(d,b),f=(new c.JavaScriptCompiler).compile(e,b,void 0,!0);return c.template(f)}function e(a,b){return f||(f=d()),f.call(this,a,b)}if(void 0===b&&(b={}),null==a||"string"!=typeof a&&"Program"!==a.type)throw new k["default"]("You must pass a string or Handlebars AST to Handlebars.compile. You passed "+a);"data"in b||(b.data=!0),b.compat&&(b.useDepths=!0);var f=void 0;return e._setup=function(a){return f||(f=d()),f._setup(a)},e._child=function(a,b,c,e){return f||(f=d()),f._child(a,b,c,e)},e}function g(a,b){if(a===b)return!0;if(l.isArray(a)&&l.isArray(b)&&a.length===b.length){for(var c=0;cc;c++){var d=this.opcodes[c],e=a.opcodes[c];if(d.opcode!==e.opcode||!g(d.args,e.args))return!1}b=this.children.length;for(var c=0;b>c;c++)if(!this.children[c].equals(a.children[c]))return!1;return!0},guid:0,compile:function(a,b){this.sourceNode=[],this.opcodes=[],this.children=[],this.options=b,this.stringParams=b.stringParams,this.trackIds=b.trackIds,b.blockParams=b.blockParams||[];var c=b.knownHelpers;if(b.knownHelpers={helperMissing:!0,blockHelperMissing:!0,each:!0,"if":!0,unless:!0,"with":!0,log:!0,lookup:!0},c)for(var d in c)d in c&&(b.knownHelpers[d]=c[d]);return this.accept(a)},compileProgram:function(a){var b=new this.compiler,c=b.compile(a,this.options),d=this.guid++;return this.usePartial=this.usePartial||c.usePartial,this.children[d]=c,this.useDepths=this.useDepths||c.useDepths,d},accept:function(a){if(!this[a.type])throw new k["default"]("Unknown type: "+a.type,a);this.sourceNode.unshift(a);var b=this[a.type](a);return this.sourceNode.shift(),b},Program:function(a){this.options.blockParams.unshift(a.blockParams);for(var b=a.body,c=b.length,d=0;c>d;d++)this.accept(b[d]);return this.options.blockParams.shift(),this.isSimple=1===c,this.blockParams=a.blockParams?a.blockParams.length:0,this},BlockStatement:function(a){h(a);var b=a.program,c=a.inverse;b=b&&this.compileProgram(b),c=c&&this.compileProgram(c);var d=this.classifySexpr(a);"helper"===d?this.helperSexpr(a,b,c):"simple"===d?(this.simpleSexpr(a),this.opcode("pushProgram",b),this.opcode("pushProgram",c),this.opcode("emptyHash"),this.opcode("blockValue",a.path.original)):(this.ambiguousSexpr(a,b,c),this.opcode("pushProgram",b),this.opcode("pushProgram",c),this.opcode("emptyHash"),this.opcode("ambiguousBlockValue")),this.opcode("append")},DecoratorBlock:function(a){var b=a.program&&this.compileProgram(a.program),c=this.setupFullMustacheParams(a,b,void 0),d=a.path;this.useDecorators=!0,this.opcode("registerDecorator",c.length,d.original)},PartialStatement:function(a){this.usePartial=!0;var b=a.program;b&&(b=this.compileProgram(a.program));var c=a.params;if(c.length>1)throw new k["default"]("Unsupported number of partial arguments: "+c.length,a);c.length||(this.options.explicitPartialContext?this.opcode("pushLiteral","undefined"):c.push({type:"PathExpression",parts:[],depth:0}));var d=a.name.original,e="SubExpression"===a.name.type;e&&this.accept(a.name),this.setupFullMustacheParams(a,b,void 0,!0);var f=a.indent||"";this.options.preventIndent&&f&&(this.opcode("appendContent",f),f=""),this.opcode("invokePartial",e,d,f),this.opcode("append")},PartialBlockStatement:function(a){this.PartialStatement(a)},MustacheStatement:function(a){this.SubExpression(a),a.escaped&&!this.options.noEscape?this.opcode("appendEscaped"):this.opcode("append")},Decorator:function(a){this.DecoratorBlock(a)},ContentStatement:function(a){a.value&&this.opcode("appendContent",a.value)},CommentStatement:function(){},SubExpression:function(a){h(a);var b=this.classifySexpr(a);"simple"===b?this.simpleSexpr(a):"helper"===b?this.helperSexpr(a):this.ambiguousSexpr(a)},ambiguousSexpr:function(a,b,c){var d=a.path,e=d.parts[0],f=null!=b||null!=c;this.opcode("getContext",d.depth),this.opcode("pushProgram",b),this.opcode("pushProgram",c),d.strict=!0,this.accept(d),this.opcode("invokeAmbiguous",e,f)},simpleSexpr:function(a){var b=a.path;b.strict=!0,this.accept(b),this.opcode("resolvePossibleLambda")},helperSexpr:function(a,b,c){var d=this.setupFullMustacheParams(a,b,c),e=a.path,f=e.parts[0];if(this.options.knownHelpers[f])this.opcode("invokeKnownHelper",d.length,f);else{if(this.options.knownHelpersOnly)throw new k["default"]("You specified knownHelpersOnly, but used the unknown helper "+f,a);e.strict=!0,e.falsy=!0,this.accept(e),this.opcode("invokeHelper",d.length,e.original,n["default"].helpers.simpleId(e))}},PathExpression:function(a){this.addDepth(a.depth),this.opcode("getContext",a.depth);var b=a.parts[0],c=n["default"].helpers.scopedId(a),d=!a.depth&&!c&&this.blockParamIndex(b);d?this.opcode("lookupBlockParam",d,a.parts):b?a.data?(this.options.data=!0,this.opcode("lookupData",a.depth,a.parts,a.strict)):this.opcode("lookupOnContext",a.parts,a.falsy,a.strict,c):this.opcode("pushContext")},StringLiteral:function(a){this.opcode("pushString",a.value)},NumberLiteral:function(a){this.opcode("pushLiteral",a.value)},BooleanLiteral:function(a){this.opcode("pushLiteral",a.value)},UndefinedLiteral:function(){this.opcode("pushLiteral","undefined")},NullLiteral:function(){this.opcode("pushLiteral","null")},Hash:function(a){var b=a.pairs,c=0,d=b.length;for(this.opcode("pushHash");d>c;c++)this.pushParam(b[c].value);for(;c--;)this.opcode("assignToHash",b[c].key);this.opcode("popHash")},opcode:function(a){this.opcodes.push({opcode:a,args:o.call(arguments,1),loc:this.sourceNode[0].loc})},addDepth:function(a){a&&(this.useDepths=!0)},classifySexpr:function(a){var b=n["default"].helpers.simpleId(a.path),c=b&&!!this.blockParamIndex(a.path.parts[0]),d=!c&&n["default"].helpers.helperExpression(a),e=!c&&(d||b);if(e&&!d){var f=a.path.parts[0],g=this.options;g.knownHelpers[f]?d=!0:g.knownHelpersOnly&&(e=!1)}return d?"helper":e?"ambiguous":"simple"},pushParams:function(a){for(var b=0,c=a.length;c>b;b++)this.pushParam(a[b])},pushParam:function(a){var b=null!=a.value?a.value:a.original||"";if(this.stringParams)b.replace&&(b=b.replace(/^(\.?\.\/)*/g,"").replace(/\//g,".")),a.depth&&this.addDepth(a.depth),this.opcode("getContext",a.depth||0),this.opcode("pushStringParam",b,a.type),"SubExpression"===a.type&&this.accept(a);else{if(this.trackIds){var c=void 0;if(!a.parts||n["default"].helpers.scopedId(a)||a.depth||(c=this.blockParamIndex(a.parts[0])),c){var d=a.parts.slice(1).join(".");this.opcode("pushId","BlockParam",c,d)}else b=a.original||b,b.replace&&(b=b.replace(/^this(?:\.|$)/,"").replace(/^\.\//,"").replace(/^\.$/,"")),this.opcode("pushId",a.type,b)}this.accept(a)}},setupFullMustacheParams:function(a,b,c,d){var e=a.params;return this.pushParams(e),this.opcode("pushProgram",b),this.opcode("pushProgram",c),a.hash?this.accept(a.hash):this.opcode("emptyHash",d),e},blockParamIndex:function(a){for(var b=0,c=this.options.blockParams.length;c>b;b++){var d=this.options.blockParams[b],e=d&&l.indexOf(d,a);if(d&&e>=0)return[b,e]}}}},function(a,b,c){"use strict";function d(a){this.value=a}function e(){}function f(a,b,c,d){var e=b.popStack(),f=0,g=c.length;for(a&&g--;g>f;f++)e=b.nameLookup(e,c[f],d);return a?[b.aliasable("container.strict"),"(",e,", ",b.quotedString(c[f]),")"]:e}var g=c(1)["default"];b.__esModule=!0;var h=c(4),i=c(6),j=g(i),k=c(5),l=c(29),m=g(l);e.prototype={nameLookup:function(a,b){return e.isValidJavaScriptVariableName(b)?[a,".",b]:[a,"[",JSON.stringify(b),"]"]},depthedLookup:function(a){return[this.aliasable("container.lookup"),'(depths, "',a,'")']},compilerInfo:function(){var a=h.COMPILER_REVISION,b=h.REVISION_CHANGES[a];return[a,b]},appendToBuffer:function(a,b,c){return k.isArray(a)||(a=[a]),a=this.source.wrap(a,b),this.environment.isSimple?["return ",a,";"]:c?["buffer += ",a,";"]:(a.appendToBuffer=!0,a)},initializeBuffer:function(){return this.quotedString("")},compile:function(a,b,c,d){this.environment=a,this.options=b,this.stringParams=this.options.stringParams,this.trackIds=this.options.trackIds,this.precompile=!d,this.name=this.environment.name,this.isChild=!!c,this.context=c||{decorators:[],programs:[],environments:[]},this.preamble(),this.stackSlot=0,this.stackVars=[],this.aliases={},this.registers={list:[]},this.hashes=[],this.compileStack=[],this.inlineStack=[],this.blockParams=[],this.compileChildren(a,b),this.useDepths=this.useDepths||a.useDepths||a.useDecorators||this.options.compat,this.useBlockParams=this.useBlockParams||a.useBlockParams;var e=a.opcodes,f=void 0,g=void 0,h=void 0,i=void 0;for(h=0,i=e.length;i>h;h++)f=e[h],this.source.currentLocation=f.loc,g=g||f.loc,this[f.opcode].apply(this,f.args);if(this.source.currentLocation=g,this.pushSource(""),this.stackSlot||this.inlineStack.length||this.compileStack.length)throw new j["default"]("Compile completed with content left on stack");this.decorators.isEmpty()?this.decorators=void 0:(this.useDecorators=!0,this.decorators.prepend("var decorators = container.decorators;\n"),this.decorators.push("return fn;"),d?this.decorators=Function.apply(this,["fn","props","container","depth0","data","blockParams","depths",this.decorators.merge()]):(this.decorators.prepend("function(fn, props, container, depth0, data, blockParams, depths) {\n"),this.decorators.push("}\n"),this.decorators=this.decorators.merge()));var k=this.createFunctionContext(d);if(this.isChild)return k;var l={compiler:this.compilerInfo(),main:k};this.decorators&&(l.main_d=this.decorators,l.useDecorators=!0);var m=this.context,n=m.programs,o=m.decorators;for(h=0,i=n.length;i>h;h++)n[h]&&(l[h]=n[h],o[h]&&(l[h+"_d"]=o[h],l.useDecorators=!0));return this.environment.usePartial&&(l.usePartial=!0),this.options.data&&(l.useData=!0),this.useDepths&&(l.useDepths=!0),this.useBlockParams&&(l.useBlockParams=!0),this.options.compat&&(l.compat=!0),d?l.compilerOptions=this.options:(l.compiler=JSON.stringify(l.compiler),this.source.currentLocation={start:{line:1,column:0}},l=this.objectLiteral(l),b.srcName?(l=l.toStringWithSourceMap({file:b.destName}),l.map=l.map&&l.map.toString()):l=l.toString()),l},preamble:function(){this.lastContext=0,this.source=new m["default"](this.options.srcName),this.decorators=new m["default"](this.options.srcName)},createFunctionContext:function(a){var b="",c=this.stackVars.concat(this.registers.list);c.length>0&&(b+=", "+c.join(", "));var d=0;for(var e in this.aliases){var f=this.aliases[e];this.aliases.hasOwnProperty(e)&&f.children&&f.referenceCount>1&&(b+=", alias"+ ++d+"="+e,f.children[0]="alias"+d)}var g=["container","depth0","helpers","partials","data"];(this.useBlockParams||this.useDepths)&&g.push("blockParams"),this.useDepths&&g.push("depths");var h=this.mergeSource(b);return a?(g.push(h),Function.apply(this,g)):this.source.wrap(["function(",g.join(","),") {\n ",h,"}"])},mergeSource:function(a){var b=this.environment.isSimple,c=!this.forceBuffer,d=void 0,e=void 0,f=void 0,g=void 0;return this.source.each(function(a){a.appendToBuffer?(f?a.prepend(" + "):f=a,g=a):(f&&(e?f.prepend("buffer += "):d=!0,g.add(";"),f=g=void 0),e=!0,b||(c=!1))}),c?f?(f.prepend("return "),g.add(";")):e||this.source.push('return "";'):(a+=", buffer = "+(d?"":this.initializeBuffer()),f?(f.prepend("return buffer + "),g.add(";")):this.source.push("return buffer;")),a&&this.source.prepend("var "+a.substring(2)+(d?"":";\n")),this.source.merge()},blockValue:function(a){var b=this.aliasable("helpers.blockHelperMissing"),c=[this.contextName(0)];this.setupHelperArgs(a,0,c);var d=this.popStack();c.splice(1,0,d),this.push(this.source.functionCall(b,"call",c))},ambiguousBlockValue:function(){var a=this.aliasable("helpers.blockHelperMissing"),b=[this.contextName(0)];this.setupHelperArgs("",0,b,!0),this.flushInline();var c=this.topStack();b.splice(1,0,c),this.pushSource(["if (!",this.lastHelper,") { ",c," = ",this.source.functionCall(a,"call",b),"}"])},appendContent:function(a){this.pendingContent?a=this.pendingContent+a:this.pendingLocation=this.source.currentLocation,this.pendingContent=a},append:function(){if(this.isInline())this.replaceStack(function(a){return[" != null ? ",a,' : ""']}),this.pushSource(this.appendToBuffer(this.popStack()));else{var a=this.popStack();this.pushSource(["if (",a," != null) { ",this.appendToBuffer(a,void 0,!0)," }"]),this.environment.isSimple&&this.pushSource(["else { ",this.appendToBuffer("''",void 0,!0)," }"])}},appendEscaped:function(){this.pushSource(this.appendToBuffer([this.aliasable("container.escapeExpression"),"(",this.popStack(),")"]))},getContext:function(a){this.lastContext=a},pushContext:function(){this.pushStackLiteral(this.contextName(this.lastContext))},lookupOnContext:function(a,b,c,d){var e=0;d||!this.options.compat||this.lastContext?this.pushContext():this.push(this.depthedLookup(a[e++])),this.resolvePath("context",a,e,b,c)},lookupBlockParam:function(a,b){this.useBlockParams=!0,this.push(["blockParams[",a[0],"][",a[1],"]"]),this.resolvePath("context",b,1)},lookupData:function(a,b,c){a?this.pushStackLiteral("container.data(data, "+a+")"):this.pushStackLiteral("data"),this.resolvePath("data",b,0,!0,c)},resolvePath:function(a,b,c,d,e){var g=this;if(this.options.strict||this.options.assumeObjects)return void this.push(f(this.options.strict&&e,this,b,a));for(var h=b.length;h>c;c++)this.replaceStack(function(e){var f=g.nameLookup(e,b[c],a);return d?[" && ",f]:[" != null ? ",f," : ",e]})},resolvePossibleLambda:function(){this.push([this.aliasable("container.lambda"),"(",this.popStack(),", ",this.contextName(0),")"])},pushStringParam:function(a,b){this.pushContext(),this.pushString(b),"SubExpression"!==b&&("string"==typeof a?this.pushString(a):this.pushStackLiteral(a))},emptyHash:function(a){this.trackIds&&this.push("{}"),this.stringParams&&(this.push("{}"),this.push("{}")),this.pushStackLiteral(a?"undefined":"{}")},pushHash:function(){this.hash&&this.hashes.push(this.hash),this.hash={values:[],types:[],contexts:[],ids:[]}},popHash:function(){var a=this.hash;this.hash=this.hashes.pop(),this.trackIds&&this.push(this.objectLiteral(a.ids)),this.stringParams&&(this.push(this.objectLiteral(a.contexts)),this.push(this.objectLiteral(a.types))),this.push(this.objectLiteral(a.values))},pushString:function(a){this.pushStackLiteral(this.quotedString(a))},pushLiteral:function(a){this.pushStackLiteral(a)},pushProgram:function(a){null!=a?this.pushStackLiteral(this.programExpression(a)):this.pushStackLiteral(null)},registerDecorator:function(a,b){var c=this.nameLookup("decorators",b,"decorator"),d=this.setupHelperArgs(b,a);this.decorators.push(["fn = ",this.decorators.functionCall(c,"",["fn","props","container",d])," || fn;"])},invokeHelper:function(a,b,c){var d=this.popStack(),e=this.setupHelper(a,b),f=c?[e.name," || "]:"",g=["("].concat(f,d);this.options.strict||g.push(" || ",this.aliasable("helpers.helperMissing")),g.push(")"),this.push(this.source.functionCall(g,"call",e.callParams))},invokeKnownHelper:function(a,b){var c=this.setupHelper(a,b);this.push(this.source.functionCall(c.name,"call",c.callParams))},invokeAmbiguous:function(a,b){this.useRegister("helper");var c=this.popStack();this.emptyHash();var d=this.setupHelper(0,a,b),e=this.lastHelper=this.nameLookup("helpers",a,"helper"),f=["(","(helper = ",e," || ",c,")"];this.options.strict||(f[0]="(helper = ",f.push(" != null ? helper : ",this.aliasable("helpers.helperMissing"))),this.push(["(",f,d.paramsInit?["),(",d.paramsInit]:[],"),","(typeof helper === ",this.aliasable('"function"')," ? ",this.source.functionCall("helper","call",d.callParams)," : helper))"])},invokePartial:function(a,b,c){var d=[],e=this.setupParams(b,1,d);a&&(b=this.popStack(),delete e.name),c&&(e.indent=JSON.stringify(c)),e.helpers="helpers",e.partials="partials",e.decorators="container.decorators",a?d.unshift(b):d.unshift(this.nameLookup("partials",b,"partial")),this.options.compat&&(e.depths="depths"),e=this.objectLiteral(e), -d.push(e),this.push(this.source.functionCall("container.invokePartial","",d))},assignToHash:function(a){var b=this.popStack(),c=void 0,d=void 0,e=void 0;this.trackIds&&(e=this.popStack()),this.stringParams&&(d=this.popStack(),c=this.popStack());var f=this.hash;c&&(f.contexts[a]=c),d&&(f.types[a]=d),e&&(f.ids[a]=e),f.values[a]=b},pushId:function(a,b,c){"BlockParam"===a?this.pushStackLiteral("blockParams["+b[0]+"].path["+b[1]+"]"+(c?" + "+JSON.stringify("."+c):"")):"PathExpression"===a?this.pushString(b):"SubExpression"===a?this.pushStackLiteral("true"):this.pushStackLiteral("null")},compiler:e,compileChildren:function(a,b){for(var c=a.children,d=void 0,e=void 0,f=0,g=c.length;g>f;f++){d=c[f],e=new this.compiler;var h=this.matchExistingProgram(d);null==h?(this.context.programs.push(""),h=this.context.programs.length,d.index=h,d.name="program"+h,this.context.programs[h]=e.compile(d,b,this.context,!this.precompile),this.context.decorators[h]=e.decorators,this.context.environments[h]=d,this.useDepths=this.useDepths||e.useDepths,this.useBlockParams=this.useBlockParams||e.useBlockParams):(d.index=h,d.name="program"+h,this.useDepths=this.useDepths||d.useDepths,this.useBlockParams=this.useBlockParams||d.useBlockParams)}},matchExistingProgram:function(a){for(var b=0,c=this.context.environments.length;c>b;b++){var d=this.context.environments[b];if(d&&d.equals(a))return b}},programExpression:function(a){var b=this.environment.children[a],c=[b.index,"data",b.blockParams];return(this.useBlockParams||this.useDepths)&&c.push("blockParams"),this.useDepths&&c.push("depths"),"container.program("+c.join(", ")+")"},useRegister:function(a){this.registers[a]||(this.registers[a]=!0,this.registers.list.push(a))},push:function(a){return a instanceof d||(a=this.source.wrap(a)),this.inlineStack.push(a),a},pushStackLiteral:function(a){this.push(new d(a))},pushSource:function(a){this.pendingContent&&(this.source.push(this.appendToBuffer(this.source.quotedString(this.pendingContent),this.pendingLocation)),this.pendingContent=void 0),a&&this.source.push(a)},replaceStack:function(a){var b=["("],c=void 0,e=void 0,f=void 0;if(!this.isInline())throw new j["default"]("replaceStack on non-inline");var g=this.popStack(!0);if(g instanceof d)c=[g.value],b=["(",c],f=!0;else{e=!0;var h=this.incrStack();b=["((",this.push(h)," = ",g,")"],c=this.topStack()}var i=a.call(this,c);f||this.popStack(),e&&this.stackSlot--,this.push(b.concat(i,")"))},incrStack:function(){return this.stackSlot++,this.stackSlot>this.stackVars.length&&this.stackVars.push("stack"+this.stackSlot),this.topStackName()},topStackName:function(){return"stack"+this.stackSlot},flushInline:function(){var a=this.inlineStack;this.inlineStack=[];for(var b=0,c=a.length;c>b;b++){var e=a[b];if(e instanceof d)this.compileStack.push(e);else{var f=this.incrStack();this.pushSource([f," = ",e,";"]),this.compileStack.push(f)}}},isInline:function(){return this.inlineStack.length},popStack:function(a){var b=this.isInline(),c=(b?this.inlineStack:this.compileStack).pop();if(!a&&c instanceof d)return c.value;if(!b){if(!this.stackSlot)throw new j["default"]("Invalid stack pop");this.stackSlot--}return c},topStack:function(){var a=this.isInline()?this.inlineStack:this.compileStack,b=a[a.length-1];return b instanceof d?b.value:b},contextName:function(a){return this.useDepths&&a?"depths["+a+"]":"depth"+a},quotedString:function(a){return this.source.quotedString(a)},objectLiteral:function(a){return this.source.objectLiteral(a)},aliasable:function(a){var b=this.aliases[a];return b?(b.referenceCount++,b):(b=this.aliases[a]=this.source.wrap(a),b.aliasable=!0,b.referenceCount=1,b)},setupHelper:function(a,b,c){var d=[],e=this.setupHelperArgs(b,a,d,c),f=this.nameLookup("helpers",b,"helper"),g=this.aliasable(this.contextName(0)+" != null ? "+this.contextName(0)+" : {}");return{params:d,paramsInit:e,name:f,callParams:[g].concat(d)}},setupParams:function(a,b,c){var d={},e=[],f=[],g=[],h=!c,i=void 0;h&&(c=[]),d.name=this.quotedString(a),d.hash=this.popStack(),this.trackIds&&(d.hashIds=this.popStack()),this.stringParams&&(d.hashTypes=this.popStack(),d.hashContexts=this.popStack());var j=this.popStack(),k=this.popStack();(k||j)&&(d.fn=k||"container.noop",d.inverse=j||"container.noop");for(var l=b;l--;)i=this.popStack(),c[l]=i,this.trackIds&&(g[l]=this.popStack()),this.stringParams&&(f[l]=this.popStack(),e[l]=this.popStack());return h&&(d.args=this.source.generateArray(c)),this.trackIds&&(d.ids=this.source.generateArray(g)),this.stringParams&&(d.types=this.source.generateArray(f),d.contexts=this.source.generateArray(e)),this.options.data&&(d.data="data"),this.useBlockParams&&(d.blockParams="blockParams"),d},setupHelperArgs:function(a,b,c,d){var e=this.setupParams(a,b,c);return e=this.objectLiteral(e),d?(this.useRegister("options"),c.push("options"),["options=",e]):c?(c.push(e),""):e}},function(){for(var a="break else new var case finally return void catch for switch while continue function this with default if throw delete in try do instanceof typeof abstract enum int short boolean export interface static byte extends long super char final native synchronized class float package throws const goto private transient debugger implements protected volatile double import public let yield await null true false".split(" "),b=e.RESERVED_WORDS={},c=0,d=a.length;d>c;c++)b[a[c]]=!0}(),e.isValidJavaScriptVariableName=function(a){return!e.RESERVED_WORDS[a]&&/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(a)},b["default"]=e,a.exports=b["default"]},function(a,b,c){"use strict";function d(a,b,c){if(f.isArray(a)){for(var d=[],e=0,g=a.length;g>e;e++)d.push(b.wrap(a[e],c));return d}return"boolean"==typeof a||"number"==typeof a?a+"":a}function e(a){this.srcFile=a,this.source=[]}b.__esModule=!0;var f=c(5),g=void 0;try{}catch(h){}g||(g=function(a,b,c,d){this.src="",d&&this.add(d)},g.prototype={add:function(a){f.isArray(a)&&(a=a.join("")),this.src+=a},prepend:function(a){f.isArray(a)&&(a=a.join("")),this.src=a+this.src},toStringWithSourceMap:function(){return{code:this.toString()}},toString:function(){return this.src}}),e.prototype={isEmpty:function(){return!this.source.length},prepend:function(a,b){this.source.unshift(this.wrap(a,b))},push:function(a,b){this.source.push(this.wrap(a,b))},merge:function(){var a=this.empty();return this.each(function(b){a.add([" ",b,"\n"])}),a},each:function(a){for(var b=0,c=this.source.length;c>b;b++)a(this.source[b])},empty:function(){var a=this.currentLocation||{start:{}};return new g(a.start.line,a.start.column,this.srcFile)},wrap:function(a){var b=arguments.length<=1||void 0===arguments[1]?this.currentLocation||{start:{}}:arguments[1];return a instanceof g?a:(a=d(a,this,b),new g(b.start.line,b.start.column,this.srcFile,a))},functionCall:function(a,b,c){return c=this.generateList(c),this.wrap([a,b?"."+b+"(":"(",c,")"])},quotedString:function(a){return'"'+(a+"").replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")+'"'},objectLiteral:function(a){var b=[];for(var c in a)if(a.hasOwnProperty(c)){var e=d(a[c],this);"undefined"!==e&&b.push([this.quotedString(c),":",e])}var f=this.generateList(b);return f.prepend("{"),f.add("}"),f},generateList:function(a){for(var b=this.empty(),c=0,e=a.length;e>c;c++)c&&b.add(","),b.add(d(a[c],this));return b},generateArray:function(a){var b=this.generateList(a);return b.prepend("["),b.add("]"),b}},b["default"]=e,a.exports=b["default"]}])}); \ No newline at end of file diff --git a/doc/vendor/jquery.min.js b/doc/vendor/jquery.min.js deleted file mode 100644 index 349030de9..000000000 --- a/doc/vendor/jquery.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v2.2.1 | (c) jQuery Foundation | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="2.2.1",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!k.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=d.createElement("script"),b.text=a,d.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:h.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(d=e.call(arguments,2),f=function(){return a.apply(b||this,d.concat(e.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return h.call(b,a)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&f.parentNode&&(this.length=1,this[0]=f),this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?void 0!==c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?h.call(n(a),this[0]):h.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||n.uniqueSort(e),D.test(a)&&e.reverse()),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.removeEventListener("DOMContentLoaded",J),a.removeEventListener("load",J),n.ready()}n.ready.promise=function(b){return I||(I=n.Deferred(),"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(n.ready):(d.addEventListener("DOMContentLoaded",J),a.addEventListener("load",J))),I.promise(b)},n.ready.promise();var K=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)K(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},L=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function M(){this.expando=n.expando+M.uid++}M.uid=1,M.prototype={register:function(a,b){var c=b||{};return a.nodeType?a[this.expando]=c:Object.defineProperty(a,this.expando,{value:c,writable:!0,configurable:!0}),a[this.expando]},cache:function(a){if(!L(a))return{};var b=a[this.expando];return b||(b={},L(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[b]=c;else for(d in b)e[d]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=a[this.expando];if(void 0!==f){if(void 0===b)this.register(a);else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in f?d=[b,e]:(d=e,d=d in f?[d]:d.match(G)||[])),c=d.length;while(c--)delete f[d[c]]}(void 0===b||n.isEmptyObject(f))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!n.isEmptyObject(b)}};var N=new M,O=new M,P=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Q=/[A-Z]/g;function R(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Q,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:P.test(c)?n.parseJSON(c):c}catch(e){}O.set(a,b,c); -}else c=void 0;return c}n.extend({hasData:function(a){return O.hasData(a)||N.hasData(a)},data:function(a,b,c){return O.access(a,b,c)},removeData:function(a,b){O.remove(a,b)},_data:function(a,b,c){return N.access(a,b,c)},_removeData:function(a,b){N.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=O.get(f),1===f.nodeType&&!N.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),R(f,d,e[d])));N.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){O.set(this,a)}):K(this,function(b){var c,d;if(f&&void 0===b){if(c=O.get(f,a)||O.get(f,a.replace(Q,"-$&").toLowerCase()),void 0!==c)return c;if(d=n.camelCase(a),c=O.get(f,d),void 0!==c)return c;if(c=R(f,d,void 0),void 0!==c)return c}else d=n.camelCase(a),this.each(function(){var c=O.get(this,d);O.set(this,d,b),a.indexOf("-")>-1&&void 0!==c&&O.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){O.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=N.get(a,b),c&&(!d||n.isArray(c)?d=N.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return N.get(a,c)||N.access(a,c,{empty:n.Callbacks("once memory").add(function(){N.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length",""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};$.optgroup=$.option,$.tbody=$.tfoot=$.colgroup=$.caption=$.thead,$.th=$.td;function _(a,b){var c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function aa(a,b){for(var c=0,d=a.length;d>c;c++)N.set(a[c],"globalEval",!b||N.get(b[c],"globalEval"))}var ba=/<|&#?\w+;/;function ca(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],o=0,p=a.length;p>o;o++)if(f=a[o],f||0===f)if("object"===n.type(f))n.merge(m,f.nodeType?[f]:f);else if(ba.test(f)){g=g||l.appendChild(b.createElement("div")),h=(Y.exec(f)||["",""])[1].toLowerCase(),i=$[h]||$._default,g.innerHTML=i[1]+n.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;n.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",o=0;while(f=m[o++])if(d&&n.inArray(f,d)>-1)e&&e.push(f);else if(j=n.contains(f.ownerDocument,f),g=_(l.appendChild(f),"script"),j&&aa(g),c){k=0;while(f=g[k++])Z.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var da=/^key/,ea=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,fa=/^([^.]*)(?:\.(.+)|)/;function ga(){return!0}function ha(){return!1}function ia(){try{return d.activeElement}catch(a){}}function ja(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ja(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=ha;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return"undefined"!=typeof n&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(G)||[""],j=b.length;while(j--)h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.hasData(a)&&N.get(a);if(r&&(i=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&N.remove(a,"handle events")}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(N.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.rnamespace||a.rnamespace.test(g.namespace))&&(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!==this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,la=/\s*$/g;function pa(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function qa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function ra(a){var b=na.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function sa(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(N.hasData(a)&&(f=N.access(a),g=N.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}O.hasData(a)&&(h=O.access(a),i=n.extend({},h),O.set(b,i))}}function ta(a,b){var c=b.nodeName.toLowerCase();"input"===c&&X.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}function ua(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);if(r||o>1&&"string"==typeof q&&!l.checkClone&&ma.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),ua(f,b,c,d)});if(o&&(e=ca(b,a[0].ownerDocument,!1,a,d),g=e.firstChild,1===e.childNodes.length&&(e=g),g||d)){for(h=n.map(_(e,"script"),qa),i=h.length;o>m;m++)j=e,m!==p&&(j=n.clone(j,!0,!0),i&&n.merge(h,_(j,"script"))),c.call(a[m],j,m);if(i)for(k=h[h.length-1].ownerDocument,n.map(h,ra),m=0;i>m;m++)j=h[m],Z.test(j.type||"")&&!N.access(j,"globalEval")&&n.contains(k,j)&&(j.src?n._evalUrl&&n._evalUrl(j.src):n.globalEval(j.textContent.replace(oa,"")))}return a}function va(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(_(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&aa(_(d,"script")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(ka,"<$1>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=_(h),f=_(a),d=0,e=f.length;e>d;d++)ta(f[d],g[d]);if(b)if(c)for(f=f||_(a),g=g||_(h),d=0,e=f.length;e>d;d++)sa(f[d],g[d]);else sa(a,h);return g=_(h,"script"),g.length>0&&aa(g,!i&&_(a,"script")),h},cleanData:function(a){for(var b,c,d,e=n.event.special,f=0;void 0!==(c=a[f]);f++)if(L(c)){if(b=c[N.expando]){if(b.events)for(d in b.events)e[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);c[N.expando]=void 0}c[O.expando]&&(c[O.expando]=void 0)}}}),n.fn.extend({domManip:ua,detach:function(a){return va(this,a,!0)},remove:function(a){return va(this,a)},text:function(a){return K(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.appendChild(a)}})},prepend:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(_(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return K(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!la.test(a)&&!$[(Y.exec(a)||["",""])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(_(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return ua(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(_(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),f=e.length-1,h=0;f>=h;h++)c=h===f?this:this.clone(!0),n(e[h])[b](c),g.apply(d,c.get());return this.pushStack(d)}});var wa,xa={HTML:"block",BODY:"block"};function ya(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],"display");return c.detach(),d}function za(a){var b=d,c=xa[a];return c||(c=ya(a,b),"none"!==c&&c||(wa=(wa||n("